diff --git a/package-lock.json b/package-lock.json
index dd802009..40a3c787 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13,6 +13,7 @@
"@chakra-ui/react": "^2.8.2",
"@emotion/react": "^11.11.3",
"@emotion/styled": "^11.11.0",
+ "@tanstack/react-query": "^5.51.23",
"dayjs": "^1.11.11",
"framer-motion": "^10.18.0",
"jotai": "^2.6.1",
@@ -1930,6 +1931,30 @@
"tslib": "^2.4.0"
}
},
+ "node_modules/@tanstack/query-core": {
+ "version": "5.51.21",
+ "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.51.21.tgz",
+ "integrity": "sha512-POQxm42IUp6n89kKWF4IZi18v3fxQWFRolvBA6phNVmA8psdfB1MvDnGacCJdS+EOX12w/CyHM62z//rHmYmvw==",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/tannerlinsley"
+ }
+ },
+ "node_modules/@tanstack/react-query": {
+ "version": "5.51.23",
+ "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.51.23.tgz",
+ "integrity": "sha512-CfJCfX45nnVIZjQBRYYtvVMIsGgWLKLYC4xcUiYEey671n1alvTZoCBaU9B85O8mF/tx9LPyrI04A6Bs2THv4A==",
+ "dependencies": {
+ "@tanstack/query-core": "5.51.21"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/tannerlinsley"
+ },
+ "peerDependencies": {
+ "react": "^18.0.0"
+ }
+ },
"node_modules/@types/hoist-non-react-statics": {
"version": "3.3.5",
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz",
diff --git a/package.json b/package.json
index 5a9e920a..b388253b 100644
--- a/package.json
+++ b/package.json
@@ -14,6 +14,7 @@
"@chakra-ui/react": "^2.8.2",
"@emotion/react": "^11.11.3",
"@emotion/styled": "^11.11.0",
+ "@tanstack/react-query": "^5.51.23",
"dayjs": "^1.11.11",
"framer-motion": "^10.18.0",
"jotai": "^2.6.1",
diff --git a/public/images/crops/growth/carrot/1.png b/public/images/crops/growth/carrot/1.png
new file mode 100644
index 00000000..cc092f92
Binary files /dev/null and b/public/images/crops/growth/carrot/1.png differ
diff --git a/public/images/crops/growth/carrot/2.png b/public/images/crops/growth/carrot/2.png
new file mode 100644
index 00000000..cbf846d8
Binary files /dev/null and b/public/images/crops/growth/carrot/2.png differ
diff --git a/public/images/crops/growth/carrot/3.png b/public/images/crops/growth/carrot/3.png
new file mode 100644
index 00000000..06920ccd
Binary files /dev/null and b/public/images/crops/growth/carrot/3.png differ
diff --git a/public/images/crops/growth/carrot/4.png b/public/images/crops/growth/carrot/4.png
new file mode 100644
index 00000000..2d61a07b
Binary files /dev/null and b/public/images/crops/growth/carrot/4.png differ
diff --git a/public/images/crops/growth/carrot/5.png b/public/images/crops/growth/carrot/5.png
new file mode 100644
index 00000000..534719d6
Binary files /dev/null and b/public/images/crops/growth/carrot/5.png differ
diff --git a/public/images/crops/growth/pea/1.png b/public/images/crops/growth/pea/1.png
new file mode 100644
index 00000000..bc3e9656
Binary files /dev/null and b/public/images/crops/growth/pea/1.png differ
diff --git a/public/images/crops/growth/pea/2.png b/public/images/crops/growth/pea/2.png
new file mode 100644
index 00000000..462d8787
Binary files /dev/null and b/public/images/crops/growth/pea/2.png differ
diff --git a/public/images/crops/growth/pea/3.png b/public/images/crops/growth/pea/3.png
new file mode 100644
index 00000000..814b0402
Binary files /dev/null and b/public/images/crops/growth/pea/3.png differ
diff --git a/public/images/crops/growth/pea/4.png b/public/images/crops/growth/pea/4.png
new file mode 100644
index 00000000..252d32ce
Binary files /dev/null and b/public/images/crops/growth/pea/4.png differ
diff --git a/public/images/crops/growth/pea/5.png b/public/images/crops/growth/pea/5.png
new file mode 100644
index 00000000..509283b9
Binary files /dev/null and b/public/images/crops/growth/pea/5.png differ
diff --git a/public/images/crops/growth/rice/1.png b/public/images/crops/growth/rice/1.png
new file mode 100644
index 00000000..1954b213
Binary files /dev/null and b/public/images/crops/growth/rice/1.png differ
diff --git a/public/images/crops/growth/rice/2.png b/public/images/crops/growth/rice/2.png
new file mode 100644
index 00000000..6f6523f6
Binary files /dev/null and b/public/images/crops/growth/rice/2.png differ
diff --git a/public/images/crops/growth/rice/3.png b/public/images/crops/growth/rice/3.png
new file mode 100644
index 00000000..3c67ce4f
Binary files /dev/null and b/public/images/crops/growth/rice/3.png differ
diff --git a/public/images/crops/growth/rice/4.png b/public/images/crops/growth/rice/4.png
new file mode 100644
index 00000000..9db6ea9c
Binary files /dev/null and b/public/images/crops/growth/rice/4.png differ
diff --git a/public/images/crops/growth/rice/5.png b/public/images/crops/growth/rice/5.png
new file mode 100644
index 00000000..363d3704
Binary files /dev/null and b/public/images/crops/growth/rice/5.png differ
diff --git a/public/images/crops/growth/sweetPotato/1.png b/public/images/crops/growth/sweetPotato/1.png
new file mode 100644
index 00000000..06b2b357
Binary files /dev/null and b/public/images/crops/growth/sweetPotato/1.png differ
diff --git a/public/images/crops/growth/sweetPotato/2.png b/public/images/crops/growth/sweetPotato/2.png
new file mode 100644
index 00000000..b383dd25
Binary files /dev/null and b/public/images/crops/growth/sweetPotato/2.png differ
diff --git a/public/images/crops/growth/sweetPotato/3.png b/public/images/crops/growth/sweetPotato/3.png
new file mode 100644
index 00000000..dea1ac4e
Binary files /dev/null and b/public/images/crops/growth/sweetPotato/3.png differ
diff --git a/public/images/crops/growth/sweetPotato/4.png b/public/images/crops/growth/sweetPotato/4.png
new file mode 100644
index 00000000..7677cc7b
Binary files /dev/null and b/public/images/crops/growth/sweetPotato/4.png differ
diff --git a/public/images/crops/growth/sweetPotato/5.png b/public/images/crops/growth/sweetPotato/5.png
new file mode 100644
index 00000000..d9fcb36c
Binary files /dev/null and b/public/images/crops/growth/sweetPotato/5.png differ
diff --git a/public/images/crops/growth/tomato/1.png b/public/images/crops/growth/tomato/1.png
new file mode 100644
index 00000000..e1394607
Binary files /dev/null and b/public/images/crops/growth/tomato/1.png differ
diff --git a/public/images/crops/growth/tomato/2.png b/public/images/crops/growth/tomato/2.png
new file mode 100644
index 00000000..740f94c2
Binary files /dev/null and b/public/images/crops/growth/tomato/2.png differ
diff --git a/public/images/crops/growth/tomato/3.png b/public/images/crops/growth/tomato/3.png
new file mode 100644
index 00000000..d9cd2e04
Binary files /dev/null and b/public/images/crops/growth/tomato/3.png differ
diff --git a/public/images/crops/growth/tomato/4.png b/public/images/crops/growth/tomato/4.png
new file mode 100644
index 00000000..6482cbb7
Binary files /dev/null and b/public/images/crops/growth/tomato/4.png differ
diff --git a/public/images/crops/growth/tomato/5.png b/public/images/crops/growth/tomato/5.png
new file mode 100644
index 00000000..169520f9
Binary files /dev/null and b/public/images/crops/growth/tomato/5.png differ
diff --git a/public/images/curriculumCrops/carrot_5.png b/public/images/curriculumCrops/carrot_5.png
deleted file mode 100644
index 59fbc365..00000000
Binary files a/public/images/curriculumCrops/carrot_5.png and /dev/null differ
diff --git a/src/app/api/login.ts b/src/app/api/login.ts
index ccf0f545..f3edc2ea 100644
--- a/src/app/api/login.ts
+++ b/src/app/api/login.ts
@@ -3,10 +3,10 @@ import { fetcher } from '@/app/api/fetcher';
const loginFetcher = fetcher();
-const postGoogleLogin = (code: string | null) =>
+const postGoogleLogin = (code: string | null, redirectUri: string | undefined) =>
loginFetcher('/login/google', {
method: 'POST',
- body: { code },
+ body: { code, redirectUri },
});
export { postGoogleLogin };
diff --git a/src/app/api/member.ts b/src/app/api/member.ts
index e20e4e67..fb2ee8c3 100644
--- a/src/app/api/member.ts
+++ b/src/app/api/member.ts
@@ -1,4 +1,7 @@
+/* eslint-disable import/prefer-default-export */
+import { useQuery } from '@tanstack/react-query';
import { fetcher } from '@/app/api/fetcher';
+import useGetUser from '@/hooks/useGetUser';
const memberFetcher = fetcher();
@@ -17,4 +20,12 @@ const patchStudyMandate = (token: string, studyId: number, newStudyLeaderId: num
},
});
-export { getSidebarInfo, patchStudyMandate };
+const useGetSideBarInfoQuery = () => {
+ const user = useGetUser();
+ return useQuery({
+ queryFn: () => getSidebarInfo(user?.token || '', user?.memberId || 0),
+ queryKey: ['sidebar', user?.memberId],
+ });
+};
+
+export { getSidebarInfo, useGetSideBarInfoQuery, patchStudyMandate };
diff --git a/src/app/oauth2/code/google/page.tsx b/src/app/oauth2/code/google/page.tsx
index 4343bdf8..d93753ee 100644
--- a/src/app/oauth2/code/google/page.tsx
+++ b/src/app/oauth2/code/google/page.tsx
@@ -16,7 +16,7 @@ const Page = ({ searchParams }: { searchParams: { code: string } }) => {
useEffect(() => {
if (code) {
- postGoogleLogin(code).then((res) => {
+ postGoogleLogin(code, process.env.NEXT_PUBLIC_GOOGLE_REDIRECT_URL).then((res) => {
if (res?.ok) {
setUser({
memberId: res.body?.memberId,
diff --git a/src/app/providers.tsx b/src/app/providers.tsx
index 523e91d9..f4b89796 100644
--- a/src/app/providers.tsx
+++ b/src/app/providers.tsx
@@ -1,17 +1,21 @@
'use client';
import { ChakraProvider } from '@chakra-ui/react';
+import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { Provider, createStore } from 'jotai';
import theme from '@/theme';
const store = createStore();
+const queryClient = new QueryClient();
const Providers = ({ children }: { children: React.ReactNode }) => {
return (
-
- {children}
-
+
+
+ {children}
+
+
);
};
diff --git a/src/app/team/[teamId]/join/page.tsx b/src/app/team/[teamId]/join/page.tsx
index 5579980b..493d5d13 100644
--- a/src/app/team/[teamId]/join/page.tsx
+++ b/src/app/team/[teamId]/join/page.tsx
@@ -9,6 +9,7 @@ import { loginBackPathAtom } from '@/atom';
import GOOGLE_LOGIN_URL from '@/constants/googleLoginUrl';
import { useMutateWithToken } from '@/hooks/useFetchWithToken';
import useGetUser from '@/hooks/useGetUser';
+import useRefetchSideBar from '@/hooks/useRefetchSideBar';
const Page = ({ searchParams }: { searchParams: { code: string } }) => {
const params = useParams<{ teamId: string }>();
@@ -18,12 +19,14 @@ const Page = ({ searchParams }: { searchParams: { code: string } }) => {
const user = useGetUser();
const setLoginBackPath = useSetAtom(loginBackPathAtom);
const joinTeam = useMutateWithToken(postJoinTeam);
+ const refetchSidebar = useRefetchSideBar();
useEffect(() => {
if (user) {
if (user.isLogin) {
joinTeam(teamId, code).then((res) => {
if (res?.ok) {
+ refetchSidebar();
router.replace(`/team/${teamId}`);
} else {
alert('유효하지 않은 초대링크입니다.');
@@ -35,7 +38,7 @@ const Page = ({ searchParams }: { searchParams: { code: string } }) => {
window.location.href = GOOGLE_LOGIN_URL;
}
}
- }, [user, teamId, code, router, setLoginBackPath, joinTeam]);
+ }, [user, teamId, code, router, setLoginBackPath, joinTeam, refetchSidebar]);
return
;
};
diff --git a/src/app/team/[teamId]/study/[studyId]/page.tsx b/src/app/team/[teamId]/study/[studyId]/page.tsx
index f20d99cb..dcfddcaf 100644
--- a/src/app/team/[teamId]/study/[studyId]/page.tsx
+++ b/src/app/team/[teamId]/study/[studyId]/page.tsx
@@ -10,7 +10,7 @@ import { getStudy } from '@/app/api/study';
import DocumentCard from '@/components/DocumentCard';
import Title from '@/components/Title';
import CurriculumCard from '@/containers/study/CurriculumCard';
-import Feed from '@/containers/study/Feed';
+// import Feed from '@/containers/study/Feed';
import DeleteStudyModal from '@/containers/study/Modal/DeleteStudyModal';
import StudyModal from '@/containers/study/Modal/StudyModal';
import TerminateStudyModal from '@/containers/study/Modal/TerminateStudyModal';
@@ -61,7 +61,10 @@ const Page = ({ params }: { params: { teamId: number; studyId: number } }) => {
/>
-
+ {studyData && (
+
+ )}
+
{
-
+ {/* */}
{studyData && (
{
const [isTeamModalOpen, setIsTeamModalOpen] = useState(false);
const user = useGetUser();
- const sidebarInfo = useGetFetchWithToken(getSidebarInfo, [user?.memberId], user);
+ const setUser = useSetAtom(userAtom);
+ const { data: sidebarInfo } = useGetSideBarInfoQuery();
return (
<>
@@ -48,16 +50,16 @@ const SidebarContent = ({ isOpen, setIsOpen }: SidebarContentProps) => {
/>
-
+
{isOpen && (
- {user?.isLogin ? sidebarInfo?.name : '비회원'}
+ {user?.isLogin ? sidebarInfo?.body?.name : '비회원'}
)}
} onClick={() => {}} />
} onClick={() => {}} />
- } onClick={() => {}} />
+ } onClick={() => setUser(defaultUserAtom)} />
{isOpen && user?.isLogin && (
@@ -87,7 +89,7 @@ const SidebarContent = ({ isOpen, setIsOpen }: SidebarContentProps) => {
bg="green_dark"
roundedBottom="2xl"
>
- {sidebarInfo?.myTeamsAndStudies?.map((team: SidebarTeam) => (
+ {sidebarInfo?.body?.myTeamsAndStudies?.map((team: SidebarTeam) => (
{
w={!isDesktop && isOpen ? '100%' : '0'}
h="100%"
bg={!isDesktop && isOpen ? 'rgba(0,0,0,0.5)' : ''}
+ onClick={() => {
+ setIsOpen(false);
+ }}
>
-
+ e.stopPropagation()}
+ >
diff --git a/src/constants/crop.ts b/src/constants/crop.ts
index de7e62db..7fd0dd18 100644
--- a/src/constants/crop.ts
+++ b/src/constants/crop.ts
@@ -1,9 +1,9 @@
const CROP = [
- { id: 1, name: '토마토', imageUrl: '/images/crops/tomato.png' },
- { id: 2, name: '고구마', imageUrl: '/images/crops/sweet_potato.png' },
- { id: 3, name: '당근', imageUrl: '/images/crops/carrot.png' },
- { id: 4, name: '완두콩', imageUrl: '/images/crops/pea.png' },
- { id: 5, name: '벼', imageUrl: '/images/crops/rice.png' },
+ { id: 1, name: '토마토', engName: 'tomato', imageUrl: '/images/crops/tomato.png' },
+ { id: 2, name: '고구마', engName: 'sweetPotato', imageUrl: '/images/crops/sweet_potato.png' },
+ { id: 3, name: '당근', engName: 'carrot', imageUrl: '/images/crops/carrot.png' },
+ { id: 4, name: '완두콩', engName: 'pea', imageUrl: '/images/crops/pea.png' },
+ { id: 5, name: '벼', engName: 'rice', imageUrl: '/images/crops/rice.png' },
];
export default CROP;
diff --git a/src/containers/study/CurriculumCard/index.tsx b/src/containers/study/CurriculumCard/index.tsx
index 28145c0d..28474d63 100644
--- a/src/containers/study/CurriculumCard/index.tsx
+++ b/src/containers/study/CurriculumCard/index.tsx
@@ -6,13 +6,15 @@ import { useState } from 'react';
import { MdOutlineArrowForwardIos } from 'react-icons/md';
import { getCurriculum } from '@/app/api/study';
+import CROP from '@/constants/crop';
import { useGetFetchWithToken } from '@/hooks/useFetchWithToken';
import { Curriculum } from '@/types';
import CurriculumItem from './CurriculumItem';
+import { CurriculumCardProps } from './types';
import CurriculumModal from '../CurriculumModal';
-const CurriculumCard = () => {
+const CurriculumCard = ({ cropId, studyProgressRatio }: CurriculumCardProps) => {
const [isStudyLeader] = useState(true); // NOTE 추후 스터디장 여부 props로 받아올 예정
const { studyId } = useParams<{ studyId: string }>();
@@ -20,6 +22,14 @@ const CurriculumCard = () => {
const { isOpen: isCurriculumModalOpen, onOpen: onActionModalOpen, onClose: onCurriculumModalClose } = useDisclosure();
+ const getCropImage = () => {
+ const engName = CROP.find((crop) => crop.id === cropId)?.engName;
+ const growthLevel = studyProgressRatio === 0 ? 1 : Math.ceil(studyProgressRatio / 20);
+ const cropImageURL = `/images/crops/growth/${engName}/${growthLevel}.png`;
+
+ return cropImageURL;
+ };
+
return (
{isStudyLeader && (
@@ -38,7 +48,7 @@ const CurriculumCard = () => {
borderBottomLeftRadius="2xl"
borderBottomRightRadius="0"
alt="curriculum card"
- src="/images/curriculumCrops/carrot_5.png"
+ src={getCropImage()}
/>
{
const deletedStudy = useMutateWithToken(deleteStudy);
+ const refetchSidebar = useRefetchSideBar();
const handleClickDelete = () => {
deletedStudy(id).then((res) => {
if (res.ok) {
+ refetchSidebar();
setIsOpen(false);
}
});
diff --git a/src/containers/study/Modal/StudyModal/index.tsx b/src/containers/study/Modal/StudyModal/index.tsx
index bf2ca865..aba2719c 100644
--- a/src/containers/study/Modal/StudyModal/index.tsx
+++ b/src/containers/study/Modal/StudyModal/index.tsx
@@ -13,6 +13,7 @@ import Selector from '@/components/Selector';
import StyledDatePicker from '@/components/StyledDatePicker';
import CROP from '@/constants/crop';
import { useMutateWithToken } from '@/hooks/useFetchWithToken';
+import useRefetchSideBar from '@/hooks/useRefetchSideBar';
import { StudyModalProps } from './types';
@@ -40,6 +41,8 @@ const StudyModal = ({ teamId, studyId, studyInfo, isOpen, setIsModalOpen }: Stud
const createStudy = useMutateWithToken(postStudy);
const editStudy = useMutateWithToken(putEditStudy);
+ const refetchSidebar = useRefetchSideBar();
+
const onClose = () => {
setStep(1);
setName('');
@@ -74,7 +77,10 @@ const StudyModal = ({ teamId, studyId, studyInfo, isOpen, setIsModalOpen }: Stud
endDate: endDate ? dayjs(endDate).format('YYYY-MM-DD') : '',
cropId,
}).then((res) => {
- if (res.ok) onClose();
+ if (res.ok) {
+ refetchSidebar();
+ onClose();
+ }
});
} else if (studyId && studyInfo) {
editStudy(studyId, {
@@ -84,6 +90,7 @@ const StudyModal = ({ teamId, studyId, studyInfo, isOpen, setIsModalOpen }: Stud
endDate: endDate ? dayjs(endDate).format('YYYY-MM-DD') : '',
status: startDate <= new Date() ? 'IN_PROGRESS' : 'UPCOMING',
}).then((res) => {
+ refetchSidebar();
if (res.ok) onClose();
});
}
diff --git a/src/containers/study/Participant/index.tsx b/src/containers/study/Participant/index.tsx
index 3e642dcb..9d2f9279 100644
--- a/src/containers/study/Participant/index.tsx
+++ b/src/containers/study/Participant/index.tsx
@@ -13,8 +13,9 @@ const Participant = ({ participantInfos }: ParticipantProps) => {
return 0;
});
+ // Feed 없을때 임시로 maxH="45vh"로 설정 원래는 maxH="30vh"
return (
-
+
{[
{ data: leader, color: colors.orange_dark },
diff --git a/src/containers/team/DeleteTeamModal/index.tsx b/src/containers/team/DeleteTeamModal/index.tsx
index d7ef9578..046f3116 100644
--- a/src/containers/team/DeleteTeamModal/index.tsx
+++ b/src/containers/team/DeleteTeamModal/index.tsx
@@ -4,15 +4,18 @@ import { useRouter } from 'next/navigation';
import { deleteTeam as deleteTeamApi } from '@/app/api/team';
import ConfirmModal from '@/components/Modal/ConfirmModal';
import { useMutateWithToken } from '@/hooks/useFetchWithToken';
+import useRefetchSideBar from '@/hooks/useRefetchSideBar';
import { DeleteTeamModalProps } from './type';
const DeleteTeamModal = ({ id, name, isOpen, onClose }: DeleteTeamModalProps) => {
const deleteTeam = useMutateWithToken(deleteTeamApi);
+ const refetchSidebar = useRefetchSideBar();
const router = useRouter();
const handleDeleteTeamButtonClick = () => {
deleteTeam(id).then(() => {
+ refetchSidebar();
onClose();
router.replace('/');
});
diff --git a/src/containers/team/TeamModal/index.tsx b/src/containers/team/TeamModal/index.tsx
index 530a2727..4e40aeb2 100644
--- a/src/containers/team/TeamModal/index.tsx
+++ b/src/containers/team/TeamModal/index.tsx
@@ -9,6 +9,7 @@ import IconBox from '@/components/IconBox';
import ActionModal from '@/components/Modal/ActionModal';
import S3_URL from '@/constants/s3Url';
import { useMutateWithToken } from '@/hooks/useFetchWithToken';
+import useRefetchSideBar from '@/hooks/useRefetchSideBar';
import { TeamModalProps } from './type';
@@ -33,6 +34,8 @@ const TeamModal = ({ teamInfo, isOpen, onClose }: TeamModalProps) => {
const editTeam = useMutateWithToken(putEditTeam);
const editTeamImage = useMutateWithToken(patchEditTeamImage);
+ const refetchSideBar = useRefetchSideBar();
+
const resetState = () => {
setName('');
setDescription('');
@@ -75,6 +78,7 @@ const TeamModal = ({ teamInfo, isOpen, onClose }: TeamModalProps) => {
}
});
}
+ refetchSideBar();
resetAndCloseModal();
}
});
@@ -96,6 +100,7 @@ const TeamModal = ({ teamInfo, isOpen, onClose }: TeamModalProps) => {
createTeam(teamForm).then((res) => {
if (res.ok) {
+ refetchSideBar();
resetAndCloseModal();
}
});
diff --git a/src/hooks/useRefetchSideBar.ts b/src/hooks/useRefetchSideBar.ts
new file mode 100644
index 00000000..11bd199c
--- /dev/null
+++ b/src/hooks/useRefetchSideBar.ts
@@ -0,0 +1,16 @@
+import { useQueryClient } from '@tanstack/react-query';
+
+import useGetUser from '@/hooks/useGetUser';
+
+const useRefetchSideBar = () => {
+ const queryClient = useQueryClient();
+ const user = useGetUser();
+ const refetchSideBar = () => {
+ queryClient.invalidateQueries({
+ queryKey: ['sidebar', user?.memberId],
+ });
+ };
+ return refetchSideBar;
+};
+
+export default useRefetchSideBar;