Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[배포] 3월 14일 배포 #181

Merged
merged 25 commits into from
Mar 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
eb96598
feat: Toast 컴포넌트 생성
jjswan Jan 25, 2024
22a25e8
refactor: Toast props 수정
jjswan Jan 30, 2024
50e432d
refactor: toast 조건 리팩토링
jjswan Feb 25, 2024
73a3499
refactor: toast 스타일 리팩토링
jjswan Feb 25, 2024
b304c62
refactor: toast 숫자 제한 수정 리팩토링
jjswan Feb 25, 2024
c18a8f2
refactor: 토스트 컴포넌트 리팩토링
jjswan Feb 25, 2024
738648b
qrpage 바로가기, 인쇄 모달 수정중, 다운로드, 크게 보기
soave424 Feb 28, 2024
b9ade5b
refactor: 랜덤픽 결과 글자 크기 변화
jjswan Feb 28, 2024
d743a85
인쇄 모달 수정중
soave424 Feb 28, 2024
2813e9d
refactor: Toast 훅 만들기
jjswan Feb 28, 2024
f0b270a
refactor: Toast 훅으로 변경
jjswan Feb 29, 2024
370304e
refactor: toast를 hook으로 변경
jjswan Mar 6, 2024
326d461
qr print option
soave424 Mar 6, 2024
5da0931
qr update
soave424 Mar 7, 2024
67017b6
Merge pull request #177 from choco-team/175-fe-qrcode-page
nlom0218 Mar 8, 2024
be2da5f
refactor: show Toast 수정
jjswan Mar 12, 2024
814af89
Merge branch 'develop' into 171-toast-생성
nlom0218 Mar 13, 2024
3f975a7
Merge pull request #176 from choco-team/171-toast-생성
nlom0218 Mar 13, 2024
9c52d9e
refactor: 파일 구조 및 QrCode 스펠링 변경
nlom0218 Mar 13, 2024
1d3828c
refactor: QrCode 컴포넌트 리팩터링
nlom0218 Mar 13, 2024
a2302a1
refactor: QrCodeStorage 컴포넌트 리팩터링
nlom0218 Mar 13, 2024
6f8859a
refactor: QrCodeBlock 컴포넌트 리팩터링
nlom0218 Mar 13, 2024
d355c70
refactor: QrCodeInput 컴포넌트 리팩터링
nlom0218 Mar 13, 2024
6925d18
refactor: QrCodePrintOption, QrCOdePrintPage 리팩터링
nlom0218 Mar 13, 2024
2dc6bd8
Merge pull request #179 from choco-team/178-fe-qrcode-페이지-타입-파일-구조-리팩터링
nlom0218 Mar 14, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,20 @@
"-": "^0.0.1",
"@tanstack/react-query": "^4.35.7",
"@tanstack/react-query-devtools": "^4.36.1",
"D": "^1.0.0",
"ag-grid-community": "^30.2.0",
"ag-grid-react": "^30.2.0",
"axios": "^1.5.1",
"calendar-in-react": "^1.0.5",
"chalk": "^5.3.0",
"D": "^1.0.0",
"date-fns": "^2.30.0",
"qrcode.react": "^3.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-icons": "^4.11.0",
"react-router-dom": "^6.16.0",
"react-toastify": "^10.0.4",
"react-to-print": "^2.15.1",
"styled-components": "^6.0.8",
"xlsx": "^0.18.5",
"zustand": "^4.4.7"
Expand Down
4 changes: 2 additions & 2 deletions src/Router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import SignIn from '@Pages/Auth/SignIn';
import SignUp from '@Pages/Auth/SignUp';
import LunchMenu from '@Pages/ClassManagement/LunchMenu';
import Home from '@Pages/Home';
import QrcodePage from '@Pages/Qrcode/QrcodePage';
import QrCode from '@Pages/QrCode';
import StudentManagement from '@Pages/StudentManagement';
import StudentInfo from '@Pages/StudentManagement/StudentInfo';
import StudentRegister from '@Pages/StudentManagement/StudentRegister';
Expand Down Expand Up @@ -104,7 +104,7 @@ const router = createBrowserRouter([
},
{
path: ROUTE_PATH.qrCode,
element: <QrcodePage />,
element: <QrCode />,
},
{
path: ROUTE_PATH.favorites,
Expand Down
42 changes: 42 additions & 0 deletions src/hooks/toast/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React, { createContext, useContext } from 'react';
import { toast, ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';

type ToastContextType = {
showToast: (message: string, type: 'success' | 'error' | 'warning') => void;
};

const ToastContext = createContext<ToastContextType>({ showToast: () => {} });

export const useToast = () => {
const context = useContext(ToastContext);
return context;
};

export const ToastProvider = ({ children }: { children: React.ReactNode }) => {
const showToast = (
message: string,
type: 'success' | 'error' | 'warning',
) => {
switch (type) {
case 'success':
toast.success(message);
break;
case 'error':
toast.error(message);
break;
case 'warning':
toast.warning(message);
break;
}
};

return (
<>
<ToastContainer position="bottom-right" autoClose={2000} />
<ToastContext.Provider value={{ showToast }}>
{children}
</ToastContext.Provider>
</>
);
};
6 changes: 6 additions & 0 deletions src/hooks/toast/style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { ToastContainer } from 'react-toastify';
import styled from 'styled-components';

export const StyledToastContainer = styled(ToastContainer)`
color: pink;
`;
53 changes: 28 additions & 25 deletions src/pages/App/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { PiSunBold, PiMoonStarsBold } from 'react-icons/pi';
import { Outlet, useLocation } from 'react-router-dom';
import { ThemeProvider } from 'styled-components';

import { ToastProvider } from '@Hooks/toast';
import { useMediaInit } from '@Hooks/useMedia';

import route from '@Utils/route';
Expand Down Expand Up @@ -35,31 +36,33 @@ function App() {
return (
<>
<GlobalStyle />
<ThemeProvider theme={isLightTheme ? lightTheme : darkTheme}>
<QueryProvider>
<AuthErrorBoundary>
<UserProvider>
{main === 'auth' ? (
<Outlet />
) : (
<ModalProvider>
<Header pathname={pathname} />
<S.DefaultPageLayout>
<SideNavLink pathname={pathname} />
<S.PageWrapper>
<Outlet />
</S.PageWrapper>
<S.ThemeToggleButton onClick={toggleTheme}>
{isLightTheme ? <PiSunBold /> : <PiMoonStarsBold />}
</S.ThemeToggleButton>
</S.DefaultPageLayout>
</ModalProvider>
)}
</UserProvider>
</AuthErrorBoundary>
<ReactQueryDevtools initialIsOpen={false} />
</QueryProvider>
</ThemeProvider>
<ToastProvider>
<ThemeProvider theme={isLightTheme ? lightTheme : darkTheme}>
<QueryProvider>
<AuthErrorBoundary>
<UserProvider>
{main === 'auth' ? (
<Outlet />
) : (
<ModalProvider>
<Header pathname={pathname} />
<S.DefaultPageLayout>
<SideNavLink pathname={pathname} />
<S.PageWrapper>
<Outlet />
</S.PageWrapper>
<S.ThemeToggleButton onClick={toggleTheme}>
{isLightTheme ? <PiSunBold /> : <PiMoonStarsBold />}
</S.ThemeToggleButton>
</S.DefaultPageLayout>
</ModalProvider>
)}
</UserProvider>
</AuthErrorBoundary>
<ReactQueryDevtools initialIsOpen={false} />
</QueryProvider>
</ThemeProvider>
</ToastProvider>
</>
);
}
Expand Down
22 changes: 9 additions & 13 deletions src/pages/Qrcode/QrcodeBlock/index.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import React, { useState } from 'react';

import * as S from './style';

const QrcodeBlock = () => {
const [isSelected, setIsSelected] = useState(false);

const toggleSelection = () => {
setIsSelected(!isSelected);
};
type QrCodeBlockProps = {
data: string;
isSelected: boolean;
onClick: () => void;
};

const QrCodeBlock = ({ data, isSelected, onClick }: QrCodeBlockProps) => {
return (
<S.Storage onClick={toggleSelection} isSelected={isSelected}>
<S.Storage onClick={onClick} $isSelected={isSelected}>
<S.ImageContainer>
<img
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKQAAACkCAYAAAAZtYVBAAAAAXNSR0IArs4c6QAACnZJREFUeF7tndFy2zAMBJ3//+h0pm+SOtrZHqjQ8fUVFAAeliDkOOnX9/f396v/qsAmCnwVyE0q0TT+KlAgC8JWChTIrcrRZApkGdhKgQK5VTmaTIEsA1spUCC3KkeTKZBlYCsFCuRW5WgyBbIMbKVAgdyqHE2mQJaBrRQokFuVo8kUyDKwlQIFcqtyNJkYyK+vr0dVpK9vnvOh9ZQ8+bN2ine2n/OneOfnd6sP7b9AgkIEgLVTQQpk2EJ2O4EEiAWC/Fm7jd8OKRUrkMeRhQCS8r7IH/WT3epD+x+/skkgSohmIOufCjLtj65c2v/qfO1+bb6p/wIpf8eNgCmQ2e8MFsgCSU3w1k4ztHVeIAukZeaw/u2ATK842nDqn6ph49sZivInf2l+FJ9GEIpP+l7eGdLfy6aEVm849U+C2f0RQPTSRgDQ8/atPNWP9CF9C2R4RduCU0EICAKcgLB2ynd6/wWyQN7OgAXypIA9gdRhrMC0nuzUkVZfuav1s/5Jr4/vkHZG04Kevmzy9JVrgbEH2vrX+n3aS02BPH5wXSDhyNgTaAUtkAVSde0USLoi0xlObeY/FlP+q2dUStnWh/z9+hmSClog2yHVIbEn0HaMAlkgC6RQgDq8PYC03s7gtmGIrf9d+vZfriBBSUASjACh58lugaH9WDvlR3bKn55/fIa0CU1fqVQgyq9A3itUIE8/+muHdL9CMX3ACmSBPLQsAoLsdEOQfdr/+AxJG0jtdAXXnr1FT9fH+iuQ8LNn6gDvZreA2PXpSFAgC6Rl7nZ9gfwwoNKRZJS+fzj7cSBXb5D805VpP0ay6yk+2dN45+dTIEjv1fb4yl6dIPmfLngKiO1gabwCSYQ8bC+QR8HbIR8G0HaU1evpQJDd5md/EPDD5dHh4yubBCcBbca2A0znR/FtPOuP9KKRgZ4nO+VLz5O9QMo/uEoFKZCE3L29QBZIRRAdSOXsH4sLZIFUDG0PZDqU08xDAtAVOZ0fVW/1zJzulz4movzTeqF+6a/BThc8FTwF2Man/VMByJ4CkAJmASb9ab/xlU0FsYJaIKbXW3+0fyoA2a1+Nh/yXyCH//IDFYgKYk88dSQCcBoAyof2P50P7T/ukNRRpu0kEAFIz1MBSVDyT/kRIHRAKH/r3/qz+lz0SGfIaeBIsLTg9DwVwApuAaL9W392vxSf/Fl9CuRJAVsAK7gFiPKx/ggg21DIn9WnQBbIgwK/Dkg7E9F6OoF0pdoOMt2RKD51EALE6pfqaZ+P95/OkCQQJWgBs+ttfikQtN8Cea9A/JZtC07r7Ymk9RSvHdL9b76pXngg2yHvf22UOp7tqFiQ8HNY8k9Apc+TXuR/vENiQPlLWbYDUnxrpxHB+iMgyE7xCAi7H8qH4lG+42/ZOmCBHH3LtQe2QJ4UoyuOBJs+kXSgKB96noBJ9SD/NENT/u2Q8P3EAnmPEOljD9jbA0knnk5sKmgqIOVPduo49Py0nfIhveh526HJ3/hLDQlaILM/n0f6TndAAqhAyiudCmgPiPU37Z/iF0j50mILROvphFIByT9daTRiTPun/Xw8kCQAFSwV+Gn/6X7tFUj6EPA2nl1P+lt/8QyZFogE381/mo8u0OKf3Nh86EZK/RXIcCZdXqAC6RhPO0Y75L3epE+vbOCVBEzt0wWglxY6nnaGogOcxrP+KX+qF+Vr7fGVTYBQwa2d4lkBKD75o4Kuzjf1T/kXyIdnpgJ5/PodAU4A0wEmezuk/H9v0pcYe6XaeNY/AfZ2HZIEoA3TiaSCUHw6kdMdcrqA1h+tt3pR/Sge6X+pf/qNcdogbahArn3Lnj5wVC9b7wJ5UmC6YOMdI5ypp/dXIIcBmh4BqOBxxyiQ9tY/rqcOsfqKt4BQPhZgApDi2eftersfSwPlQ/5+/C2bBMINyN/RIWApHj1PBSmQMDOnLzV2pkgLksYjoAqk+z3ttKGMv9SkgKQbsiNCgTwqnuqR1m8cSOp41HFoQxY4imcLQOvJTvujfNP9p/lRfWlEof0VSPmTGSoo2QukQzJ+qaET5NJ5vajAZKd49nlaT/YCSRU5fUqTvtQUyPu/DVQgHwYyfamhDkMzip2xKF4KkJP/ujo94HZ/ab5UH+s/vrILpJX8fn2BHEZ8umNRetPx2iHdAaP6OG+vVzuk/CUvK7Bd3w45jbisQFoAGe7yFm+fp468eoSx+VJ5SX963uZD68c7JAWkgtnn7fpU4AJpFXfrC6TT61UgpWByeYG0gi3+fuL0xzZ0I/y6K9t2DFl/XG7jpwWwz9v1tGHaL8WjTxHoeTowdABwf9M/qUkTooRpBqX4VnCKN11g2n+BBIVIIBI4tdv4BfKoOHU8e+CoIVC94xnSAkEJWbuNXyA/HEgLgF1PAFt/dj3FJ7s9UNYfraeO9rgeq2dIuyG7ngS3/ux6ik/2AnlUaPmVbQts19uC25mI1lN8shfIAnlQIB3qCTiyF8iHgaSPTWiGSQtqC247NPknu9VnOj+rL62P67l6hrSC04atvxQIurLJP9nT/aT5kd50ACg++b/sv0Cergz5dTQCjuwFslf27aGljkAzp7UXyIeBTDsEtfx4ZpFfliCAKF+yW6DpAFE8stt8yB/ZH//YhwCyApM/FKBA3kpUIGGGGx+iC2SBvFOgHfL+97ypY9GNYO0UL72hxt+y7Qan19OMau22A9sDRPu3Bab9UTx6PrVT/AIZ/m2fp19qqKAETPo8+Sc7xS+QBfLAAAGV2gskAEczUa/sbIa1I8d4h5yeoehExRuWb9Xp/qbztfqkHY72n+6vQBbI6Mq2NwgdoAJZIAukPSV369Mrgq6w6bfo6XxJS5qRU/vbdci0AATEtKC2wJQf+Vttt/rTjGjztfGXX9lpQlTwAnmPiNW/QMojR1estcvw+NfSpgtq80uv0On87YFoh5QVJ4GnCyrTuyynfOkGejr+40DagqVXMj1PHYU6LhWUgCA9KH+yp0BZfWi9zefx70NSgiR4aicBC+RRIdKb9KR6t0OeFCDBbcez66mgdECo41ogbD603sZvh5Q/++6Vff+fc9KBJEA/DkjbEakDkT8qgC0g5WM71nQHtvv5+CubACI7FXwaGOrIKfAFEhQkIH7aXiDvC9gOCV+WsB2AgC+QBfKgQAoMXXEWYPJnOwbFp3irRwaKn9p/3UsNdTASjIBYXXCKb/On9fbAkL/UXiBPChIQBTJF7v75Alkg1xImvS8HUuZzWU4dK/1YJM2PrrzV+dNMneZn80/1LJChgmnB0wNVIOUVF9Y7/r8F0/j0fIEkhZy9HdLpdVldIEMBzw1u+i/ozqZ39ZZeUekVSR8r0cxFdtKP3vLTA0L5kZ3yJ/t4h6SAqb1AZt+2IaBSe1rfAin/HmU75PFAUEe2gBbIAnlg5u07pD0BXV8F7hSIO2TlrQKTChTISTXrK1agQMYS1sGkAgVyUs36ihUokLGEdTCpQIGcVLO+YgUKZCxhHUwqUCAn1ayvWIECGUtYB5MKFMhJNesrVqBAxhLWwaQCBXJSzfqKFSiQsYR1MKlAgZxUs75iBQpkLGEdTCrwB0/OVwUeBcUiAAAAAElFTkSuQmCC"
Expand All @@ -19,12 +17,10 @@ const QrcodeBlock = () => {
</S.ImageContainer>
<S.TextContainer>
<S.TextSpan>패들렛으로 만들었던 학생작품</S.TextSpan>
<S.TextSpan>
https://nyjyangji.padlet.org/soave4242/4-1-2-6tsejdfooh969wo3
</S.TextSpan>
<S.TextSpan>{data}</S.TextSpan>
</S.TextContainer>
</S.Storage>
);
};

export default QrcodeBlock;
export default QrCodeBlock;
9 changes: 7 additions & 2 deletions src/pages/Qrcode/QrcodeBlock/style.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import styled from 'styled-components';

export const Storage = styled.div`
background-color: ${(props) => (props.isSelected ? '#fee3e2' : 'white')};
type StorageProps = {
$isSelected: boolean;
};

export const Storage = styled.div<StorageProps>`
background-color: ${({ $isSelected }) => ($isSelected ? '#fee3e2' : 'white')};
cursor: pointer;
padding: 20px;
margin: 10px;
Expand All @@ -11,6 +15,7 @@ export const Storage = styled.div`

&:hover {
background-color: #fee3e2;
border: 1px solid #fe6f61;
}
`;

Expand Down
41 changes: 28 additions & 13 deletions src/pages/Qrcode/QrcodeInput/index.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
import QRCode from 'qrcode.react';
import { useState } from 'react';
import React, { useState } from 'react';

import useModal from '@Hooks/useModal';

import * as S from './style';
import QrcodeName from '../QrcodeName';
import QrCodeName from '../QrCodeName';
import QrCodePrintOption from '../QrCodePrintOption';

function QrcodeInput() {
const [inputValue, setInputValue] = useState('');
function QrCodeInput() {
const [inputValue, setInputValue] = useState<string>('');

const { isOpen, openModal, closeModal } = useModal();
const { openModal } = useModal();

const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setInputValue(event.target.value);
};

const handleClearClick = () => {
setInputValue('');
};
Expand All @@ -23,14 +25,16 @@ function QrcodeInput() {
const url = canvas ? canvas.toDataURL('image/png') : '';
const link = document.createElement('a');
link.href = url;
link.download = `qrcode.png`;
link.download = `qrCode.png`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};

const handleViewLarger = () => {
const canvas = document.querySelector('canvas');
const qrCodeDataURL = canvas ? canvas.toDataURL('image/png') : '';
const newWindow = window.open(qrCodeDataURL, 'qrcodePopup');
const newWindow = window.open(qrCodeDataURL, 'qrCodePopup');
if (newWindow) {
newWindow.document.write(`
<div style="display: flex; justify-content: center; align-items: center; height: 100vh;">
Expand All @@ -40,35 +44,46 @@ function QrcodeInput() {
}
};

const handleGoToLink = () => {
if (inputValue) {
const url =
inputValue.startsWith('http://') || inputValue.startsWith('https://')
? inputValue
: `https://${inputValue}`;
window.open(url, '_blank');
}
};

const isButtonVisible = inputValue.trim() !== '';

return (
<S.Container>
{/* <h1>URL 주소를 입력해주세요.</h1> */}
<S.InputContainer>
<S.Input
type="url"
placeholder="www.teachercan.com"
value={inputValue}
onChange={handleInputChange}
/>
<S.ClearButton onClick={handleClearClick}>새QR생성</S.ClearButton>
<S.ClearButton onClick={handleClearClick}>새 QR 생성</S.ClearButton>
</S.InputContainer>

{isButtonVisible && <QRCode value={inputValue} size={400} />}
{isButtonVisible && (
<S.ButtonContainer>
<S.Button onClick={handleViewLarger}>크게보기</S.Button>
<S.Button>인쇄하기</S.Button>
<S.Button onClick={() => openModal(<QrCodePrintOption />)}>
인쇄하기
</S.Button>
<S.Button onClick={handleDownload}>다운로드</S.Button>
<S.Button onClick={() => openModal(<QrcodeName />)}>
<S.Button onClick={handleGoToLink}>바로가기</S.Button>
<S.Button onClick={() => openModal(<QrCodeName />)}>
보관함에 저장
</S.Button>
</S.ButtonContainer>
)}
{isOpen && <QrcodeName />}
</S.Container>
);
}

export default QrcodeInput;
export default QrCodeInput;
4 changes: 2 additions & 2 deletions src/pages/Qrcode/QrcodeInput/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export const Container = styled.div`
display: flex;
flex-direction: column;
align-items: center;
margin-top: 30px;
/* margin-top: 30px; */
padding: 10px;
width: 100%;
`;
Expand Down Expand Up @@ -45,7 +45,7 @@ export const Input = styled.input`
export const ClearButton = styled.div`
padding: 10px 20px;
height: 35px;
width: 100px;
width: fit-content;
text-align: center;
font-size: 14px;
background-color: #f48d8d;
Expand Down
4 changes: 2 additions & 2 deletions src/pages/Qrcode/QrcodeName/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Input from '@Components/Input';

import * as S from './style';

const QrcodeName = () => {
const QrCodeName = () => {
return (
<S.Container>
<S.NameSpan>저장할 QR코드 이름</S.NameSpan>
Expand All @@ -13,4 +13,4 @@ const QrcodeName = () => {
);
};

export default QrcodeName;
export default QrCodeName;
Loading
Loading