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

User info desktop/#81 #83

Merged
merged 9 commits into from
Apr 21, 2024
8 changes: 7 additions & 1 deletion app/(sub-page)/my/page.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import LectureSearch from '@/app/ui/lecture/lecture-search';
import TakenLecture from '@/app/ui/lecture/taken-lecture';
import UserInfoNavigator, { UserInfoNavigatorSkeleton } from '@/app/ui/user/user-info-navigator/user-info-navigator';
import ContentContainer from '@/app/ui/view/atom/content-container';
import Drawer from '@/app/ui/view/molecule/drawer/drawer';
import { DIALOG_KEY } from '@/app/utils/key/dialog.key';
import { Suspense } from 'react';

export default function MyPage() {
return (
<>
<ContentContainer className="flex">
<div className="hidden lg:w-[30%] lg:block">์ •๋ณด์นธ</div>
<div className="hidden lg:w-[30%] lg:block">
<Suspense fallback={<UserInfoNavigatorSkeleton />}>
<UserInfoNavigator />
</Suspense>
</div>
<div className="w-full lg:w-[70%] lg:px-[20px]">
<TakenLecture />
</div>
Expand Down
4 changes: 2 additions & 2 deletions app/mocks/handlers/user-handler.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ export const userHandlers = [
}),
http.get<never, never, UserInfoResponse | ErrorResponseData>(`${API_PATH.user}`, async ({ request }) => {
const accessToken = request.headers.get('Authorization')?.replace('Bearer ', '');
if (!accessToken) {
if (accessToken === 'undefined' || !accessToken) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

accessToken ์ด "undefined"์ธ ๊ฒฝ์šฐ์— ๋Œ€ํ•ด ์„ค๋ช…ํ•ด์ฃผ์‹ค ์ˆ˜ ์žˆ๋‚˜์š”??

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

headers: {
        Authorization: `Bearer ${cookies().get('accessToken')?.value}`,
      },
  • ์œ„์™€ ๊ฐ™์ด ํ—ค๋”๋ฅผ ์ถ”๊ฐ€ํ•˜๋‹ค ๋ณด๋‹ˆ, accessToken์ด ์—†๋Š” ๊ฒฝ์šฐ์— 'undefined'๊ฐ€ ๋ฆฌํ„ฐ๋Ÿด ๊ฐ’์œผ๋กœ ๋“ค์–ด๊ฐ€๋Š” ๊ฒฝ์šฐ๋ฅผ ํ™•์ธํ•˜์˜€๊ณ , ์ด์— ๋”ฐ๋ผ ์ˆ˜์ •ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

return HttpResponse.json({ status: 401, message: 'Unauthorized' }, { status: 401 });
}

const userInfo = mockDatabase.getUserInfo(mockDecryptToken(accessToken).authId);
await delay(500);
await delay(3000);

if (!userInfo) {
return HttpResponse.json({ status: 401, message: 'Unauthorized' }, { status: 401 });
Expand Down
41 changes: 41 additions & 0 deletions app/ui/user/user-info-navigator/user-info-navigator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import Avatar from '../../view/atom/avatar/avatar';
import Button from '../../view/atom/button/button';
import { getUserInfo } from '@/app/business/user/user.query';
import Skeleton from '../../view/atom/skeleton';

export default async function UserInfoNavigator() {
const userInfo = await getUserInfo();

return (
<div className="flex flex-col items-center p-4 ">
<Avatar className="w-24 h-24" alt="Profile picture" src={'/assets/profile-image.png'} />

<div className="my-5 text-lg">
<span className="font-semibold">{userInfo.studentName}</span>
<span>๋‹˜</span>
</div>
<div className="mb-3 text-sm">{userInfo.major}</div>
<div className="text-sm text-gray-400">{userInfo.studentNumber}</div>

<div className="mt-9">
<Button size="sm" variant="secondary" label="๋กœ๊ทธ์•„์›ƒ" />
</div>
<div className="mt-2">
<Button size="sm" variant="text" label="ํšŒ์›ํƒˆํ‡ดํ•˜๊ธฐ" />
</div>
</div>
);
}

export function UserInfoNavigatorSkeleton() {
return (
<div className="flex flex-col items-center p-4 space-y-3">
<Skeleton className="h-24 w-24 rounded-full" />
<div className="space-y-6">
<Skeleton className="h-4 w-24" />
<Skeleton className="h-4 w-32" />
<Skeleton className="h-4 w-32" />
</div>
</div>
);
}
17 changes: 17 additions & 0 deletions app/ui/view/atom/avatar/avatar.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { Meta, StoryObj } from '@storybook/react';

import Avatar from './avatar';

const meta = {
title: 'ui/view/atom/Avatar',
component: Avatar,
} as Meta<typeof Avatar>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {
args: {
src: './assets/profile-image.png',
},
};
57 changes: 57 additions & 0 deletions app/ui/view/atom/avatar/avatar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
'use client';

import * as React from 'react';
import * as AvatarPrimitive from '@radix-ui/react-avatar';

import { cn } from '@/app/utils/shadcn/utils';

interface AvatarProps {
src: string;
fallback?: React.ReactNode;
alt?: string;
className?: string;
}

export default function Avatar({ src, fallback, alt, className }: AvatarProps) {
return (
<AvatarRoot className={className}>
<AvatarImage src={src} alt={alt} />
<AvatarFallback>{fallback}</AvatarFallback>
</AvatarRoot>
);
}

const AvatarRoot = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
>(({ className, ...props }, ref) => (
<AvatarPrimitive.Root
ref={ref}
className={cn('relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full', className)}
{...props}
/>
));
AvatarRoot.displayName = AvatarPrimitive.Root.displayName;

const AvatarImage = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Image>,
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
>(({ className, ...props }, ref) => (
<AvatarPrimitive.Image ref={ref} className={cn('aspect-square h-full w-full', className)} {...props} />
));
AvatarImage.displayName = AvatarPrimitive.Image.displayName;

const AvatarFallback = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Fallback>,
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
>(({ className, ...props }, ref) => (
<AvatarPrimitive.Fallback
ref={ref}
className={cn(
'flex h-full w-full items-center justify-center rounded-full bg-slate-100 dark:bg-slate-800',
className,
)}
{...props}
/>
));
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
5 changes: 5 additions & 0 deletions app/ui/view/atom/skeleton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { cn } from '@/app/utils/shadcn/utils';

export default function Skeleton({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
return <div className={cn('animate-pulse rounded-md bg-slate-100 dark:bg-slate-800', className)} {...props} />;
}
27 changes: 27 additions & 0 deletions package-lock.json

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

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"@heroicons/react": "^2.1.1",
"@mswjs/http-middleware": "^0.9.2",
"@radix-ui/react-alert-dialog": "^1.0.5",
"@radix-ui/react-avatar": "^1.0.4",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-slot": "^1.0.2",
Expand Down
Binary file added public/assets/profile-image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading