Skip to content
15 changes: 1 addition & 14 deletions app/myInfo/page.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,5 @@
'use client';

import React from 'react';
import MyInfoStyle from '../../components/MyInfoStyle';
import useMyInfo from '../../lib/hooks/useMyInfo';

export default function MyInfoPage() {
const { data: userData, isLoading, isError, error } = useMyInfo();

if (isLoading) return <div>Loading...</div>;

if (isError)
return <div>Error: {error instanceof Error ? error.message : JSON.stringify(error)}</div>;

if (!userData) return <div>로그인이 필요합니다.</div>;

return <MyInfoStyle userData={userData} />;
return <MyInfoStyle />;
}
30 changes: 25 additions & 5 deletions app/purchase/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import FinalPaymentSummary from '../../../components/payment/FinalPaymentSummary
import RaffleItemConfirmationModal from '../../../components/Modal/RaffleItemConfirmationModal';
import { getNotFreeRaffleDataDetail } from '../../../api/raffle/raffleApi';
import { postPurchaseItem } from '../../../api/raffle/purchaseItemApi';
import useAuthStore from '../../../lib/store/useAuthStore';
import Skeleton from '../../../components/Skeleton';

export default function PurchasePage({
params,
Expand All @@ -26,11 +28,13 @@ export default function PurchasePage({
const [isPurchaseChecked, setIsPurchaseChecked] = useState<boolean>(false);
const [isRaffleConfirmationModalOpen, setIsRaffleConfirmationModalOpen] =
useState<boolean>(false);
const userToken = localStorage.getItem('access_token');
const userToken = useAuthStore<string>((state) => state.userToken);

if (!userToken) {
throw new Error('userToken이 없습니다.');
}
useEffect(() => {
if (!userToken) {
router.push('/');
}
}, [userToken, router]);

const { data: raffleDetailItem } = useQuery({
queryKey: ['getNotFreeRaffleDataDetail'],
Expand Down Expand Up @@ -66,7 +70,23 @@ export default function PurchasePage({
};

if (!raffleDetailItem) {
return <div>로딩 중...</div>;
return (
<main className="container mx-auto px-4 py-8">
<h1 className="text-3xl font-bold text-center mb-8">상품 결제</h1>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
<div className="space-y-4">
<Skeleton className="h-24 w-full" />
<Skeleton className="h-24 w-full" />
<Skeleton className="h-24 w-full" />
</div>
<div className="space-y-4">
<Skeleton className="h-24 w-full" />
<Skeleton className="h-24 w-full" />
<Skeleton className="h-24 w-full" />
</div>
</div>
</main>
);
}

return (
Expand Down
5 changes: 3 additions & 2 deletions components/AuthHandler.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { useEffect } from 'react';
import { useRouter } from 'next/navigation';
import Cookies from 'js-cookie';
import useAuthStore from '../lib/store/useAuthStore';

export default function AuthHandler() {
Expand All @@ -21,8 +22,8 @@ export default function AuthHandler() {
* 그리고 router를 이용하여 홈으로 이동.
*/
if (accessToken && refreshToken) {
localStorage.setItem('access_token', accessToken);
localStorage.setItem('refresh_token', refreshToken);
Cookies.set('access_token', accessToken);
Cookies.set('refresh_token', refreshToken);
setUserToken(accessToken, refreshToken);
router.replace('/');
}
Expand Down
14 changes: 12 additions & 2 deletions components/MyInfoStyle.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
'use client';

import React from 'react';
import { useRouter } from 'next/navigation';
import { UserData } from '../lib/types/user';
import useMyInfo from '../lib/hooks/useMyInfo';

export default function MyInfoStyle({ userData }: { userData: UserData }) {
export default function MyInfoStyle() {
const router = useRouter();
const { data: userData, isLoading, isError, error } = useMyInfo();

if (isLoading) return <div>로딩 중...</div>;

if (isError)
return <div>Error: {error instanceof Error ? error.message : JSON.stringify(error)}</div>;

if (!userData) return <div>로그인이 필요합니다.</div>;

const handleMemberInfoNavigation = () => {
router.push('/myInfo/memberInfo');
Expand Down
23 changes: 11 additions & 12 deletions components/ProfilePopover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ export default function ProfilePopover({ onClose }: { onClose: () => void }) {
const popoverRef = useRef<HTMLDivElement>(null);
const router = useRouter();


const handleLogout = () => {
logout();
localStorage.removeItem('access_token');
router.push('/');
onClose();
};

Expand All @@ -20,7 +20,6 @@ export default function ProfilePopover({ onClose }: { onClose: () => void }) {
onClose();
};


return (
<div
ref={popoverRef}
Expand All @@ -29,22 +28,22 @@ export default function ProfilePopover({ onClose }: { onClose: () => void }) {
<ul>
<li>
<Button
type='button'
label='로그아웃'
type="button"
label="로그아웃"
onClick={handleLogout}
className='text-black py-2 px-4 bg-gray-100 hover:bg-gray-200 '
width='full'
fontSize='base'
className="text-black py-2 px-4 bg-gray-100 hover:bg-gray-200 "
width="full"
fontSize="base"
/>
</li>
<li>
<Button
type='button'
label='나의 정보'
type="button"
label="나의 정보"
onClick={handleMypageNavigation}
className='text-black py-2 px-4 bg-gray-100 hover:bg-gray-200 '
width='full'
fontSize='base'
className="text-black py-2 px-4 bg-gray-100 hover:bg-gray-200 "
width="full"
fontSize="base"
/>
</li>
</ul>
Expand Down
9 changes: 9 additions & 0 deletions components/Skeleton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from 'react';

export default function Skeleton({ className }: { className?: string }) {
return (
<div className={`relative overflow-hidden bg-gray-200 ${className}`}>
<div className="absolute inset-0 animate-shimmer bg-gradient-to-r from-transparent via-gray-100 to-transparent" />
</div>
);
}
12 changes: 6 additions & 6 deletions lib/store/useAuthStore.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { create } from 'zustand';
import { createJSONStorage, persist } from 'zustand/middleware';
import { persist } from 'zustand/middleware';
import Cookies from 'js-cookie';
import { AuthStore } from '../types/authStores';

const useAuthStore = create<AuthStore>()(
Expand All @@ -9,22 +10,21 @@ const useAuthStore = create<AuthStore>()(
refreshToken: '',
setUserToken: (userToken, refreshToken) => {
if (typeof window !== 'undefined') {
localStorage.setItem('access_token', userToken);
localStorage.setItem('refresh_token', refreshToken);
Cookies.set('access_token', userToken);
Cookies.set('refresh_token', refreshToken);
}
set({ userToken, refreshToken });
},
logout: () => {
if (typeof window !== 'undefined') {
localStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');
Cookies.remove('access_token');
Cookies.remove('refresh_token');
}
set({ userToken: '', refreshToken: '' });
},
}),
{
name: 'auth-storage',
storage: typeof window !== 'undefined' ? createJSONStorage(() => localStorage) : undefined,
},
),
);
Expand Down
16 changes: 16 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"eslint-plugin-jsx-a11y": "^6.9.0",
"eslint-plugin-react": "^7.35.1",
"eslint-plugin-react-hooks": "^4.6.2",
"js-cookie": "^3.0.5",
"next": "14.2.5",
"nodemailer": "^6.9.14",
"react": "^18",
Expand All @@ -39,6 +40,7 @@
"@storybook/nextjs": "^8.2.9",
"@storybook/react": "^8.2.9",
"@storybook/test": "^8.2.9",
"@types/js-cookie": "^3.0.6",
"@types/node": "^20",
"@types/nodemailer": "^6.4.15",
"@types/react": "^18",
Expand Down
8 changes: 8 additions & 0 deletions tailwind.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ const config: Config = {
'white-shadow':
'rgb(255, 255, 255) 3px 0px 0px, rgb(255, 255, 255) 2.83487px 0.981584px 0px, rgb(255, 255, 255) 2.35766px 1.85511px 0px, rgb(255, 255, 255) 1.62091px 2.52441px 0px, rgb(255, 255, 255) 0.705713px 2.91581px 0px, rgb(255, 255, 255) -0.287171px 2.98622px 0px, rgb(255, 255, 255) -1.24844px 2.72789px 0px, rgb(255, 255, 255) -2.07227px 2.16926px 0px, rgb(255, 255, 255) -2.66798px 1.37182px 0px, rgb(255, 255, 255) -2.96998px 0.42336px 0px, rgb(255, 255, 255) -2.94502px -0.571704px 0px, rgb(255, 255, 255) -2.59586px -1.50383px 0px, rgb(255, 255, 255) -1.96093px -2.27041px 0px, rgb(255, 255, 255) -1.11013px -2.78704px 0px, rgb(255, 255, 255) -0.137119px -2.99686px 0px, rgb(255, 255, 255) 0.850987px -2.87677px 0px, rgb(255, 255, 255) 1.74541px -2.43999px 0px, rgb(255, 255, 255) 2.44769px -1.73459px 0px, rgb(255, 255, 255) 2.88051px -0.838247px 0px',
},
keyframes: {
shimmer: {
'100%': { transform: 'translateX(100%)' },
},
},
animation: {
shimmer: 'shimmer 2s infinite',
},
},

colors: {
Expand Down