diff --git a/index.html b/index.html index ed735bad..3fc1531d 100644 --- a/index.html +++ b/index.html @@ -2,10 +2,13 @@ - + - Vite + React + TS - + Studay +
diff --git a/package-lock.json b/package-lock.json index 76247f84..50df21c4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "eslint-plugin-import": "^2.29.0", "eslint-plugin-prettier": "^5.0.1", "eslint-plugin-react": "^7.33.2", + "framer-motion": "^10.16.12", "jotai": "^2.4.3", "react": "^18.2.0", "react-datepicker": "^4.21.0", @@ -2427,6 +2428,21 @@ "node": ">=10.0.0" } }, + "node_modules/@emotion/is-prop-valid": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", + "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", + "optional": true, + "dependencies": { + "@emotion/memoize": "0.7.4" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==", + "optional": true + }, "node_modules/@emotion/use-insertion-effect-with-fallbacks": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz", @@ -9692,6 +9708,29 @@ "url": "https://github.com/sponsors/rawify" } }, + "node_modules/framer-motion": { + "version": "10.16.12", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-10.16.12.tgz", + "integrity": "sha512-w7Yzx0OzQ5Uh6uNkxaX+4TuAPuOKz3haSbjmHpdrqDpGuCJCpq6YP9Dy7JJWdZ6mJjndrg3Ao3vUwDajKNikCA==", + "dependencies": { + "tslib": "^2.4.0" + }, + "optionalDependencies": { + "@emotion/is-prop-valid": "^0.8.2" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", diff --git a/package.json b/package.json index f35164e8..5d868cc9 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "eslint-plugin-import": "^2.29.0", "eslint-plugin-prettier": "^5.0.1", "eslint-plugin-react": "^7.33.2", + "framer-motion": "^10.16.12", "jotai": "^2.4.3", "react": "^18.2.0", "react-datepicker": "^4.21.0", diff --git a/src/components/BottomSheet/Dimmer.tsx b/src/components/BottomSheet/Dimmer.tsx new file mode 100644 index 00000000..66171865 --- /dev/null +++ b/src/components/BottomSheet/Dimmer.tsx @@ -0,0 +1,20 @@ +import { MouseEventHandler, RefObject } from 'react' + +export type DimmerPropsType = { + dimmerRef: RefObject + onClick: MouseEventHandler +} + +const Dimmer = ({ dimmerRef, onClick }: DimmerPropsType) => { + return ( +
+ ) +} + +export default Dimmer diff --git a/src/components/common/button/Button.tsx b/src/components/common/button/Button.tsx index bc7e7d9a..7eaa1f03 100644 --- a/src/components/common/button/Button.tsx +++ b/src/components/common/button/Button.tsx @@ -41,8 +41,8 @@ const Button = ({ } ${BUTTON_TEXT_COLOR['blue500']} ${BUTTON_BORDER_COLOR['blue500']}` : buttonType === 'Plain-disabled' ? `${BUTTON_RADIUS['middle']} ${ - fullWidth ? 'w-full' : width ? 'w-[317px]' : BUTTON_WIDTH[width] - } ${height ? 'h-[43px]' : BUTTON_HEIGHT[height]} ${ + fullWidth ? 'w-full' : width ? 'w-[343px]' : BUTTON_WIDTH[width] + } ${height ? 'h-[56px]' : BUTTON_HEIGHT[height]} ${ BUTTON_BG_COLOR['white0'] } ${BUTTON_TEXT_COLOR['gray500']} ${BUTTON_BORDER_COLOR['gray500']}` : buttonType === 'Plain-red' diff --git a/src/components/common/header/Header.tsx b/src/components/common/header/Header.tsx index 75dcc603..636b406e 100644 --- a/src/components/common/header/Header.tsx +++ b/src/components/common/header/Header.tsx @@ -66,7 +66,12 @@ const Header = ({ ) : headerType === 'CloseWithTitle' ? (
- navigate(-1)}> + 0 + ? () => navigate(backUrl) + : () => navigate(-1) + }> {pageTitle} diff --git a/src/components/common/inputbox/input/Input.tsx b/src/components/common/inputbox/input/Input.tsx index e70a018b..7fd74986 100644 --- a/src/components/common/inputbox/input/Input.tsx +++ b/src/components/common/inputbox/input/Input.tsx @@ -21,7 +21,6 @@ const Input = forwardRef( ) => { const [inputValue, setInputValue] = useState('') const [searchInputValue, setSearchInputValue] = useState('') - return inputType === 'Default' ? (
( className={`${ fullWidth ? 'w-full h-[52px]' : 'w-[323px] h-[52px]' } rounded-[10px] ${ - field === 'email' && - !validate('email', inputValue) && + (field === 'email' || + field === 'nickname' || + field === 'childname') && + !validate(field, inputValue) && inputValue !== '' ? 'border border-red-600' - : field === 'nickname' && - !validate('nickname', inputValue) && - inputValue !== '' - ? 'border border-red-600' : 'border border-blue-350' } px-[20px] font-nsk text-black-800 bg-white-200 body-18 placeholder:text-gray-600 outline-none`} value={inputValue} @@ -54,8 +51,8 @@ const Input = forwardRef( />

{field === 'email' && - !validate('email', inputValue) && - inputValue !== '' + inputValue !== '' && + !validate('email', inputValue) ? (errorMessage = '잘못된 이메일입니다') : field === 'nickname' && !validate('nickname', inputValue) && diff --git a/src/components/common/label/LabelType.ts b/src/components/common/label/LabelType.ts index 87b80821..8bb34d53 100644 --- a/src/components/common/label/LabelType.ts +++ b/src/components/common/label/LabelType.ts @@ -20,7 +20,7 @@ export const LabelColorVariant = { export const LabelTextColorVariant = { default: { - medium: 'stroke-blue-500 text-blue-500 ', + medium: 'stroke-blue-500 text-blue-500', small: 'text-white-0' }, selected: { diff --git a/src/components/common/profile/Profile.tsx b/src/components/common/profile/Profile.tsx index c56587bc..0e6d3617 100644 --- a/src/components/common/profile/Profile.tsx +++ b/src/components/common/profile/Profile.tsx @@ -19,27 +19,27 @@ const Profile = ({ const handleImageChange = (editId: number) => { if (imgRef.current && imgRef.current?.files) { + setImage(URL.createObjectURL(imgRef.current.files[0])) const formData = new FormData() formData.append('file', imgRef.current.files[0], 'myfile') - try { - request - .post(`/children/${editId}/profile`, formData, { - headers: { - 'Content-Type': 'multipart/form-data' - } - }) - .then((res) => { - setImage(res.data.profileImageUrl) + request + .post(`/children/${editId}/profile`, formData, { + headers: { + 'Content-Type': 'multipart/form-data' + } + }) + .then(() => { + setToast({ + comment: '프로필 사진을 수정했어요.', + type: 'success' }) - .catch(() => { - setToast({ - comment: '파일 용량이 너무 커서 업로드를 실패했어요.', - type: 'error' - }) + }) + .catch(() => { + setToast({ + comment: '파일 용량이 너무 커서 업로드를 실패했어요.', + type: 'error' }) - } catch { - setToast({ comment: '파일 업로드를 실패했어요.', type: 'error' }) - } + }) } } return ( @@ -81,7 +81,7 @@ const Profile = ({ {imageLabel && (

{imageLabel}

diff --git a/src/components/common/scheduleBox/ScheduleBox.tsx b/src/components/common/scheduleBox/ScheduleBox.tsx index ee9b3438..f924172d 100644 --- a/src/components/common/scheduleBox/ScheduleBox.tsx +++ b/src/components/common/scheduleBox/ScheduleBox.tsx @@ -37,8 +37,12 @@ const ScheduleBox = ({
{mainTitle}
)}
- - +
+ +
+
+ +
diff --git a/src/components/common/scheduleBox/ScheduleBoxType.ts b/src/components/common/scheduleBox/ScheduleBoxType.ts index 91160e47..1272a7b3 100644 --- a/src/components/common/scheduleBox/ScheduleBoxType.ts +++ b/src/components/common/scheduleBox/ScheduleBoxType.ts @@ -8,7 +8,7 @@ export interface ScheduleBoxProps extends ComponentProps<'div'> { rightBottomElement?: ReactNode // HTML태그를 넣을 수 있음! isRegister?: boolean cntOfChild?: number - handleToggle?: () => void - handleEdit?: () => void - handleDelete?: () => void + handleToggle?: (e: React.MouseEvent) => void + handleEdit?: (e: React.MouseEvent) => void + handleDelete?: (e: React.MouseEvent) => void } diff --git a/src/components/common/toast/index.tsx b/src/components/common/toast/index.tsx index 5d15f848..e1bb0bd8 100644 --- a/src/components/common/toast/index.tsx +++ b/src/components/common/toast/index.tsx @@ -3,10 +3,11 @@ const Toast = () => { return ( > + bottomSheetState: boolean }) => { + const [isOpen, setOpen] = useState(false) + const [outsideRef, handleClickEditProfileDimmer] = useOutsideClick(() => + setOpen(false) + ) + + useEffect(() => { + setOpen(bottomSheetState) + }, [bottomSheetState]) + const { setToast } = useToastify() + const [reviewCount, setReviewCount] = useState([]) const [reviewState, setReviewState] = useState({ academyId: academyId, KINDNESS: false, @@ -29,34 +43,51 @@ const ReviewBottomSheet = ({ }) const reviewMutation = useMutation({ mutationFn: (reviewState: ReviewRequestType) => postReview(reviewState), + onSettled: (data) => { + queryClient.invalidateQueries({ + queryKey: ['isReview', data?.academyId] + }) + }, onSuccess: () => { - setBottomSheetClose(false) + setOpen(false) setToast({ comment: '리뷰를 성공적으로 남겼어요.', type: 'success' }) } }) - const handleMemo = (value: keyof ReviewRequestType) => { - if (reviewState[value]) { + const handleMemo = (value: string) => { + if (reviewCount.includes(value)) { setReviewState({ ...reviewState, [value]: false }) + setReviewCount(reviewCount.filter((data) => data !== value)) } else { setReviewState({ ...reviewState, [value]: true }) + setReviewCount([...reviewCount, value]) } } - useEffect(() => { - const valueAry = Object.values(reviewState) - const count = valueAry.filter(Boolean).length - if (count >= 4) - setToast({ comment: '리뷰는 4개 이상 남길 수 없어요.', type: 'warning' }) - }, [reviewState]) + return ( <> -
+ {isOpen ? ( + + ) : ( + '' + )} +
@@ -87,10 +118,27 @@ const ReviewBottomSheet = ({ return (
-
+ ) } diff --git a/src/components/selectcity/CityStep.tsx b/src/components/selectcity/CityStep.tsx index 168642f3..ac9be327 100644 --- a/src/components/selectcity/CityStep.tsx +++ b/src/components/selectcity/CityStep.tsx @@ -41,11 +41,11 @@ const CityStep = ({ return [PROVINCE_TEXT, CITY_TEXT, TOWN_TEXT] }, []) - useEffect(()=>{ - if(selectRef.current){ + useEffect(() => { + if (selectRef.current) { selectRef.current.selectedIndex = 0 } - },[currentStep]) + }, [currentStep]) return ( <> @@ -85,7 +85,7 @@ const CityStep = ({ text={StepQuestionTitle[currentStep - 1]} step={currentStep} /> -
+
{
))}
-
    + +
      {PAGE_CONTENT[currentPage].buttonType.map( (buttonLabel, i) => buttonLabel && ( @@ -180,7 +182,6 @@ const Onboarding = () => { : 'Round-blue-500' } onClick={() => { - // 아무것도 입력을 하지 않았을 때! if ( inputRef.current?.value === '' || selectRef.current?.value === '' diff --git a/src/pages/onboarding/constants.ts b/src/pages/onboarding/constants.ts index 1712bb77..913a4802 100644 --- a/src/pages/onboarding/constants.ts +++ b/src/pages/onboarding/constants.ts @@ -85,7 +85,6 @@ export const PAGE_CONTENT = [ ] export const CHILD_GRADE = [ - '', '초등학교 1학년', '초등학교 2학년', '초등학교 3학년', diff --git a/src/pages/schedule/Schedule.tsx b/src/pages/schedule/Schedule.tsx index 219a6c37..bdeead58 100644 --- a/src/pages/schedule/Schedule.tsx +++ b/src/pages/schedule/Schedule.tsx @@ -2,6 +2,7 @@ import { useMemo, useState } from 'react' import { useNavigate } from 'react-router-dom' import { useQuery } from '@tanstack/react-query' import { CalenderType } from '../../types/date.ts' +import Loading from '@/components/Loading/Loading.tsx' import Calender from '@/components/common/calender/Calender.tsx' import Icon from '@/components/common/icon/Icon.tsx' import Profile from '@/components/common/profile/Profile.tsx' @@ -42,7 +43,7 @@ const Schedule = () => { month: calenderState.nowMonth }) }) - const { data: scheduleData } = useQuery({ + const { data: scheduleData, isLoading } = useQuery({ queryKey: ['scheduleData', calenderState.toDay], queryFn: () => getDaySchedule({ @@ -77,7 +78,8 @@ const Schedule = () => { holidays={monthSchedule?.holidays || []} />
-
+
+ {isLoading && } {scheduleData && scheduleData.dateResponses.map((data, index) => ( <> @@ -122,7 +124,7 @@ const Schedule = () => { ))} ))} - {!scheduleData && ( + {!scheduleData && !isLoading && ( {'생성된 스케줄이 없습니다. 스케줄을 생성해주세요!'} diff --git a/src/routes/index.tsx b/src/routes/index.tsx index c2750ffa..0511da82 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -77,7 +77,10 @@ export const router = createBrowserRouter( path: 'edit/:childId/editing', element: ( <> -
+
) @@ -167,7 +170,10 @@ export const router = createBrowserRouter( path: 'academies/:dashboardId/', element: ( <> -
+
),