diff --git a/.gitignore b/.gitignore index f493cdeb2..3d9572eb8 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,5 @@ node_modules # Web .sentryclirc .next -.idea \ No newline at end of file +.idea +login \ No newline at end of file diff --git a/packages/web/package.json b/packages/web/package.json index a9259b99a..1bb1d0fca 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -39,6 +39,7 @@ "react-datepicker": "^4.15.0", "react-dom": "^18.2.0", "react-error-boundary": "^4.0.12", + "react-glider": "^4.0.2", "react-google-autocomplete": "^2.7.3", "react-hook-form": "^7.45.0", "react-i18next": "^13.2.2", @@ -47,7 +48,6 @@ "react-simple-pull-to-refresh": "^1.3.3", "server-only": "^0.0.1", "sharp": "^0.33.2", - "swiper": "^9.4.1", "tailwind-merge": "^1.14.0", "zustand": "^4.3.8" }, diff --git a/packages/web/src/apis/groups/mutations.tsx b/packages/web/src/apis/groups/mutations.tsx index ef11cc9c7..eae56200d 100644 --- a/packages/web/src/apis/groups/mutations.tsx +++ b/packages/web/src/apis/groups/mutations.tsx @@ -1,3 +1,5 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; + import { deleteArticle, deleteComment, @@ -15,10 +17,10 @@ import { Keys as GroupsKeys } from './keys'; import { GroupDetailResponse } from './type'; import { MeetingScrapResponse } from '../meeting'; import { Keys as MeetingKeys } from '../meeting/keys'; + import FeedbackCompleteModal from '@/app/[lng]/(main)/meeting/participate/feedback/[groupId]/funnels/step3/FeedbackCompleteModal.client'; import useAppRouter from '@/hooks/useAppRouter'; import { useModal } from '@/hooks/useModal'; -import { useMutation, useQueryClient } from '@tanstack/react-query'; export const usePostCreateGroup = () => { const { replace } = useAppRouter(); @@ -28,7 +30,7 @@ export const usePostCreateGroup = () => { mutationFn: postCreateGroup, onSuccess: (data) => { queryClient.resetQueries({ queryKey: GroupsKeys.getGroups() }); - replace(`/grouping/${data.groupId}`); + replace(`/grouping/${data.groupId}?tab=detail`); }, }); }; diff --git a/packages/web/src/app/[lng]/(main)/community/components/ContentSection.tsx b/packages/web/src/app/[lng]/(main)/community/components/ContentSection.tsx index 14a472100..7bb7a006f 100644 --- a/packages/web/src/app/[lng]/(main)/community/components/ContentSection.tsx +++ b/packages/web/src/app/[lng]/(main)/community/components/ContentSection.tsx @@ -1,8 +1,8 @@ 'use client'; import dynamic from 'next/dynamic'; import { Suspense } from 'react'; -import { useTranslation } from 'react-i18next'; +import { useTranslation } from '@/app/i18n/client'; import { Loading } from '@/components/Loading'; import { Tabs } from '@/components/Tabs'; diff --git a/packages/web/src/app/[lng]/(main)/grouping/[groupId]/manage/components/ManageDetail.client.tsx b/packages/web/src/app/[lng]/(main)/grouping/[groupId]/manage/components/ManageDetail.client.tsx index 858b2da07..c46b0bf83 100644 --- a/packages/web/src/app/[lng]/(main)/grouping/[groupId]/manage/components/ManageDetail.client.tsx +++ b/packages/web/src/app/[lng]/(main)/grouping/[groupId]/manage/components/ManageDetail.client.tsx @@ -1,8 +1,7 @@ 'use client'; import { useState } from 'react'; -import { Pagination } from 'swiper'; -import { Swiper, SwiperSlide } from 'swiper/react'; +import Glider from 'react-glider'; import ApplyCard from './ApplyCard.client'; @@ -13,6 +12,8 @@ import { Flex } from '@/components/Layout'; import { Spacing } from '@/components/Spacing'; import { useNumberParams } from '@/hooks/useNumberParams'; +import 'glider-js/glider.min.css'; + export default function ManageDetail() { const { t } = useTranslation('groupDetail'); const { groupId } = useNumberParams<['groupId']>(); @@ -22,6 +23,12 @@ export default function ManageDetail() { const [currentApplication, setCurrentApplication] = useState(1); + const handleSlideChange = (event: any) => { + const newSlideIndex = event.detail.slide; + console.log(newSlideIndex); + setCurrentApplication(newSlideIndex); + }; + if (!totalCount) { return ( @@ -39,24 +46,23 @@ export default function ManageDetail() {

- {currentApplication}/{totalCount} + {currentApplication + 1}/{totalCount}

- setCurrentApplication(swiper.activeIndex + 1)} + {applies.map((apply) => ( - +
- +
))} -
+ ); } diff --git a/packages/web/src/app/[lng]/(main)/grouping/create/components/LocationBottomSheet.client.tsx b/packages/web/src/app/[lng]/(main)/grouping/create/components/LocationBottomSheet.client.tsx index 0ac6d3f64..611548b4f 100644 --- a/packages/web/src/app/[lng]/(main)/grouping/create/components/LocationBottomSheet.client.tsx +++ b/packages/web/src/app/[lng]/(main)/grouping/create/components/LocationBottomSheet.client.tsx @@ -1,3 +1,4 @@ +'use client'; import { useParams } from 'next/navigation'; import { useState } from 'react'; import usePlacesService from 'react-google-autocomplete/lib/usePlacesAutocompleteService'; @@ -71,6 +72,8 @@ export default function LocationBottomSheet({ }; const handleSelect = async (place: google.maps.places.AutocompletePrediction) => { + if (!placesService) return; + placesService?.getDetails({ placeId: place.place_id }, (details) => { const lat = details?.geometry?.location?.lat(); const lng = details?.geometry?.location?.lng(); diff --git a/packages/web/src/app/[lng]/(main)/grouping/create/funnels/main/UploadSection.client.tsx b/packages/web/src/app/[lng]/(main)/grouping/create/funnels/main/UploadSection.client.tsx index dd176b295..110259cf3 100644 --- a/packages/web/src/app/[lng]/(main)/grouping/create/funnels/main/UploadSection.client.tsx +++ b/packages/web/src/app/[lng]/(main)/grouping/create/funnels/main/UploadSection.client.tsx @@ -7,6 +7,7 @@ import type { CreateGroupContextValue } from '../../type'; import { Icon } from '@/components/Icon'; import { Flex } from '@/components/Layout'; +import { Loading } from '@/components/Loading'; import { useFileUpload } from '@/hooks/useFileUpload'; interface ImageThumbnailProps { @@ -19,7 +20,7 @@ export default function UploadSection({ control }: ImageThumbnailProps) { control, }); - const { handleFileUploadClick, previewImage } = useFileUpload(async (files) => { + const { handleFileUploadClick, previewImage, isPending } = useFileUpload(async (files) => { field.onChange(files[0]); }); @@ -30,16 +31,21 @@ export default function UploadSection({ control }: ImageThumbnailProps) { className="rounded-8 bg-sub relative mx-20 aspect-[8/5] overflow-hidden" onClick={handleFileUploadClick} > - + ); } interface RenderImageProps { previewImage: string | undefined; + isPending: boolean; } -const RenderImage = memo(function ({ previewImage }: RenderImageProps) { +const RenderImage = memo(function ({ previewImage, isPending }: RenderImageProps) { + if (isPending) { + return ; + } + if (previewImage) { return group_image; } diff --git a/packages/web/src/app/[lng]/(main)/profile/components/ProfileDetailSection.client.tsx b/packages/web/src/app/[lng]/(main)/profile/components/ProfileDetailSection.client.tsx index 071cc5434..1cda6e9bc 100644 --- a/packages/web/src/app/[lng]/(main)/profile/components/ProfileDetailSection.client.tsx +++ b/packages/web/src/app/[lng]/(main)/profile/components/ProfileDetailSection.client.tsx @@ -1,6 +1,6 @@ 'use client'; -import { motion } from 'framer-motion'; +import { m } from 'framer-motion'; import Image from 'next/image'; import { useParams, usePathname } from 'next/navigation'; @@ -10,6 +10,7 @@ import { Avatar } from '@/components/Avatar'; import { Divider } from '@/components/Divider'; import { Icon } from '@/components/Icon'; import { Flex } from '@/components/Layout'; +import { Motion } from '@/components/Motion'; import { NavLink } from '@/components/NavLink'; import { Spacing } from '@/components/Spacing'; import { Tag } from '@/components/Tag'; @@ -148,12 +149,14 @@ export default function ProfileDetailSection({ profileData }: ProfileDetailProps
- + + +
diff --git a/packages/web/src/components/Animation/ButtonAnimation.tsx b/packages/web/src/components/Animation/ButtonAnimation.tsx index 3caa1ca9b..0a12ed9d4 100644 --- a/packages/web/src/components/Animation/ButtonAnimation.tsx +++ b/packages/web/src/components/Animation/ButtonAnimation.tsx @@ -1,6 +1,9 @@ 'use client'; +import { m } from 'framer-motion'; + +import { Motion } from '../Motion'; + import { StrictPropsWithChildren } from '@/types'; -import { motion } from 'framer-motion'; interface ButtonAnimationProps { className?: string; @@ -11,23 +14,25 @@ export default function ButtonAnimation({ ...props }: StrictPropsWithChildren) { return ( - ({ - scale: clicked ? 1 : 1.1, - }), - pressed: { - scale: 0.9, - }, - rest: { - scale: 1, - }, - }} - > - {children} - + + ({ + scale: clicked ? 1 : 1.1, + }), + pressed: { + scale: 0.9, + }, + rest: { + scale: 1, + }, + }} + > + {children} + + ); } diff --git a/packages/web/src/components/Calendar/Calendar.client.tsx b/packages/web/src/components/Calendar/Calendar.client.tsx index 057b90e29..bd7865d18 100644 --- a/packages/web/src/components/Calendar/Calendar.client.tsx +++ b/packages/web/src/components/Calendar/Calendar.client.tsx @@ -1,15 +1,17 @@ import 'react-datepicker/dist/react-datepicker.css'; -import { Icon } from '../Icon'; -import { Spacing } from '../Spacing'; -import { IconButton } from '@/components/Button'; -import { Flex } from '@/components/Layout'; import { format } from 'date-fns'; import { enUS, ko } from 'date-fns/esm/locale'; import { useParams } from 'next/navigation'; import { useMemo } from 'react'; import DatePicker from 'react-datepicker'; +import { Icon } from '../Icon'; +import { Spacing } from '../Spacing'; + +import { IconButton } from '@/components/Button'; +import { Flex } from '@/components/Layout'; + interface CalendarProps { dateValue: Date | null; setDateValue: (date: Date) => void; diff --git a/packages/web/src/components/Card/GroupingCard.client.tsx b/packages/web/src/components/Card/GroupingCard.client.tsx index 262c943f4..715890561 100644 --- a/packages/web/src/components/Card/GroupingCard.client.tsx +++ b/packages/web/src/components/Card/GroupingCard.client.tsx @@ -55,7 +55,7 @@ export default function GroupingCard({ return ( - +
{imageUrl ? ( { + const newSlideIndex = event.detail.slide; + setCurrentImageIndex(newSlideIndex); + }; + return ( - - setCurrentImageIndex(swiper.activeIndex)} + + {images.map((image, index) => ( - - fullImage - +
+ {`img-${index}`} +
))} - - - - {currentImageIndex + 1}/{images.length} - - -
+ + + + + {currentImageIndex + 1}/{images.length} + +
); } diff --git a/packages/web/src/components/Modal/ModalWrapper.client.tsx b/packages/web/src/components/Modal/ModalWrapper.client.tsx index 86348feb6..0dd09e25b 100644 --- a/packages/web/src/components/Modal/ModalWrapper.client.tsx +++ b/packages/web/src/components/Modal/ModalWrapper.client.tsx @@ -1,7 +1,9 @@ 'use client'; -import { motion } from 'framer-motion'; +import { m } from 'framer-motion'; import { useRef } from 'react'; +import { Motion } from '../Motion'; + import type { StrictPropsWithChildren } from '@/types'; import { fadeInVariants } from '@/constants/motions'; @@ -25,17 +27,19 @@ export default function ModalWrapper({ useOnClickOutside(modalRef, onClose); return ( - -
+ - {children} -
-
+
+ {children} +
+ + ); } diff --git a/packages/web/src/components/Modal/Toast.client.tsx b/packages/web/src/components/Modal/Toast.client.tsx index 2eba37db7..305d81303 100644 --- a/packages/web/src/components/Modal/Toast.client.tsx +++ b/packages/web/src/components/Modal/Toast.client.tsx @@ -1,7 +1,9 @@ 'use client'; -import { motion } from 'framer-motion'; +import { m } from 'framer-motion'; import { useRef } from 'react'; +import { Motion } from '../Motion'; + import { fadeInVariants } from '@/constants/motions'; import { StrictPropsWithChildren } from '@/types'; @@ -9,12 +11,14 @@ export default function Toast({ children }: StrictPropsWithChildren) { const ref = useRef(null); return ( - - {children} - + + + {children} + + ); } diff --git a/packages/web/src/components/Motion/Motion.tsx b/packages/web/src/components/Motion/Motion.tsx new file mode 100644 index 000000000..d529abca2 --- /dev/null +++ b/packages/web/src/components/Motion/Motion.tsx @@ -0,0 +1,12 @@ +import { LazyMotion, domMax } from 'framer-motion'; +import React from 'react'; + +import { StrictPropsWithChildren } from '@/types'; + +export default function Motion({ children }: StrictPropsWithChildren) { + return ( + + {children} + + ); +} diff --git a/packages/web/src/components/Motion/index.ts b/packages/web/src/components/Motion/index.ts new file mode 100644 index 000000000..4abc43540 --- /dev/null +++ b/packages/web/src/components/Motion/index.ts @@ -0,0 +1 @@ +export { default as Motion } from './Motion'; diff --git a/packages/web/src/components/Tabs/Tabs.tsx b/packages/web/src/components/Tabs/Tabs.tsx index b72b8acd4..e82542a2b 100644 --- a/packages/web/src/components/Tabs/Tabs.tsx +++ b/packages/web/src/components/Tabs/Tabs.tsx @@ -1,4 +1,4 @@ -import { LayoutGroup, motion } from 'framer-motion'; +import { LayoutGroup, m } from 'framer-motion'; import Link from 'next/link'; import { usePathname, useSearchParams } from 'next/navigation'; import { @@ -7,11 +7,11 @@ import { ReactElement, cloneElement, isValidElement, - useState, } from 'react'; import type { StrictPropsWithChildren } from '@/types'; +import { Motion } from '@/components/Motion'; import cn from '@/utils/cn'; export default function Tabs({ children }: StrictPropsWithChildren) { @@ -98,12 +98,14 @@ function Tab({ value, text, queryString, className, disabled = false }: TabProps > {text} {isActive && ( - + + + )} ); diff --git a/packages/web/src/hooks/useModal/useModal.tsx b/packages/web/src/hooks/useModal/useModal.tsx index 8625a4822..5f2343150 100644 --- a/packages/web/src/hooks/useModal/useModal.tsx +++ b/packages/web/src/hooks/useModal/useModal.tsx @@ -1,9 +1,10 @@ 'use client'; +import { useUnmountEffect } from 'framer-motion'; +import { useContext, useMemo, useRef, useState } from 'react'; + import { ModalControlRef, ModalController } from './ModalController'; import { ModalContext } from './ModalProvider'; import { CreateModalElement } from './type'; -import { useUnmountEffect } from 'framer-motion'; -import { useContext, useMemo, useRef, useState } from 'react'; let elementId = 1; diff --git a/yarn.lock b/yarn.lock index 2d08868db..8d7a2a8bd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2153,6 +2153,7 @@ __metadata: react-datepicker: ^4.15.0 react-dom: ^18.2.0 react-error-boundary: ^4.0.12 + react-glider: ^4.0.2 react-google-autocomplete: ^2.7.3 react-hook-form: ^7.45.0 react-i18next: ^13.2.2 @@ -2164,7 +2165,6 @@ __metadata: supports-color: 8.1.1 svgstore: ^3.0.1 svgstore-cli: ^2.0.1 - swiper: ^9.4.1 tailwind-merge: ^1.14.0 tailwindcss: ^3.4.1 ts-jest: ^29.1.1 @@ -8561,6 +8561,13 @@ __metadata: languageName: node linkType: hard +"glider-js@npm:^1.7.7": + version: 1.7.8 + resolution: "glider-js@npm:1.7.8" + checksum: d651e10be8b27a7038541e85fdf0cb47bc5cc43363e617612eb6ebe573d2e6c2ce43b077323ba558fb7446cc8124f16cb9d2fc5499b6c356ed7427082822f6d7 + languageName: node + linkType: hard + "glob-parent@npm:^5.1.2, glob-parent@npm:~5.1.2": version: 5.1.2 resolution: "glob-parent@npm:5.1.2" @@ -13541,6 +13548,18 @@ __metadata: languageName: node linkType: hard +"react-glider@npm:^4.0.2": + version: 4.0.2 + resolution: "react-glider@npm:4.0.2" + dependencies: + glider-js: ^1.7.7 + peerDependencies: + react: ^18.0.0 + react-dom: ^18.0.0 + checksum: 862bf79f1410b297ada45c8a6ac08631b09e4e473a31c75d55641a6eb7294619cad2b6f3d953c1e9b0ce9c24ed3005f274852ad94324d35da320b5a907a3f55a + languageName: node + linkType: hard + "react-google-autocomplete@npm:^2.7.3": version: 2.7.3 resolution: "react-google-autocomplete@npm:2.7.3" @@ -14997,13 +15016,6 @@ __metadata: languageName: node linkType: hard -"ssr-window@npm:^4.0.2": - version: 4.0.2 - resolution: "ssr-window@npm:4.0.2" - checksum: df182600927f4f3225224cf8c02338ea637c9750519505bbfb9a9236741a2a7ec088386fb948bca7b447b8303d9109e7dc7672e3de041c79ac2a0e03665af7d2 - languageName: node - linkType: hard - "ssri@npm:^10.0.0": version: 10.0.5 resolution: "ssri@npm:10.0.5" @@ -15480,15 +15492,6 @@ __metadata: languageName: node linkType: hard -"swiper@npm:^9.4.1": - version: 9.4.1 - resolution: "swiper@npm:9.4.1" - dependencies: - ssr-window: ^4.0.2 - checksum: 1180b3b766f25cbe636fafbb56adbddf8a240077c504a335a62d1773f4452df1bd9ca09bccfe86478c3b9401879c4e8f7ed3824e74299f8b48953e8fc7f08bc3 - languageName: node - linkType: hard - "symbol-tree@npm:^3.2.4": version: 3.2.4 resolution: "symbol-tree@npm:3.2.4"