Skip to content

Commit

Permalink
Merge pull request #139 from Myongji-Graduate/mypage-error/#138
Browse files Browse the repository at this point in the history
refactor: my page refactor
  • Loading branch information
gahyuun authored Sep 10, 2024
2 parents 168e144 + 62d9865 commit 4f123d7
Show file tree
Hide file tree
Showing 19 changed files with 182 additions and 66 deletions.
20 changes: 20 additions & 0 deletions app/(sub-page)/sign-in/components/sign-in-form-container.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use client';
import useDialog from '@/app/hooks/useDialog';
import SignInForm from '@/app/ui/user/sign-in-form/sign-in-form';
import { DIALOG_KEY } from '@/app/utils/key/dialog-key.util';
import React from 'react';
import UpdateInstruction from './update-instruction';
import { FormState } from '@/app/ui/view/molecule/form/form-root';

export default function SignInFormContainer() {
const { open } = useDialog(DIALOG_KEY.UPDATE_INSTRUCTION);
const handleSuccess = (formState?: FormState) => {
if (formState?.message === '재업로드') open();
};
return (
<>
<SignInForm onSuccess={handleSuccess} />
<UpdateInstruction />
</>
);
}
36 changes: 36 additions & 0 deletions app/(sub-page)/sign-in/components/update-instruction.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
'use client';
import useDialog from '@/app/hooks/useDialog';
import Button from '@/app/ui/view/atom/button/button';
import { AlertDialog, AlertDialogContent } from '@/app/ui/view/molecule/alert-dialog/alert-dialog';
import { DIALOG_KEY } from '@/app/utils/key/dialog-key.util';
import { useRouter } from 'next/navigation';

export default function UpdateInstruction() {
const router = useRouter();
const { isOpen, close } = useDialog(DIALOG_KEY.UPDATE_INSTRUCTION);
return (
<AlertDialog open={isOpen}>
<AlertDialogContent>
<div className="flex flex-col gap-4">
<div className="text-xl font-bold">업데이트 안내문</div>
<p className="text-gray-800 leading-6">
<span className="text-primary font-bold">졸업을 부탁해</span>가 2.0.2 버전으로 업데이트됨에 따라, 2024년 9월
3일 이전에 성적표를 업로드하신 모든 사용자께서는 성적표를 재업로드해 주시기 바랍니다.
<br />
감사합니다.
</p>
<Button
label="확인"
size="xs"
variant="list"
style={{ alignSelf: 'flex-end' }}
onClick={() => {
close();
router.push('/grade-upload');
}}
/>
</div>
</AlertDialogContent>
</AlertDialog>
);
}
4 changes: 2 additions & 2 deletions app/(sub-page)/sign-in/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import SignInForm from '@/app/ui/user/sign-in-form/sign-in-form';
import ContentContainer from '@/app/ui/view/atom/content-container/content-container';

import TitleBox from '@/app/ui/view/molecule/title-box/title-box';
Expand All @@ -9,6 +8,7 @@ import Button from '@/app/ui/view/atom/button/button';
import Responsive from '@/app/ui/responsive';
import Link from 'next/link';
import type { Metadata } from 'next';
import SignInFormContainer from './components/sign-in-form-container';

export const metadata: Metadata = {
title: '로그인',
Expand All @@ -27,7 +27,7 @@ export default function SignInPage() {
<div className="pb-12">
<TitleBox title={'로그인'} />
</div>
<SignInForm />
<SignInFormContainer />
<div className="flex mt-12 space-x-4 h-6 items-center justify-center">
<Link href={'/find-id'}>
<Button className="text-xs" label="아이디 찾기" variant={'text'} />
Expand Down
54 changes: 26 additions & 28 deletions app/business/services/lecture/taken-lecture.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,35 +44,33 @@ export const parsePDFtoText = async (formData: FormData) => {
};

export const deleteTakenLecture = async (lectureId: number) => {
// try {
const response = await fetch(`${API_PATH.takenLectures}/${lectureId}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${cookies().get('accessToken')?.value}`,
},
});
// http error handling에서 result가 필수값이므로 사용할 수 없음
// 하지만 fetch 가 수정되면서 바꿀 예정이므로 현재는 작동만 되도록
if (response.ok) {
revalidateTag(TAG.GET_TAKEN_LECTURES);
return {
isSuccess: true,
};
} else {
return {
isSuccess: false,
};
try {
const response = await fetch(`${API_PATH.takenLectures}/${lectureId}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${cookies().get('accessToken')?.value}`,
},
});
if (response.ok) {
revalidateTag(TAG.GET_TAKEN_LECTURES);
return {
isSuccess: true,
};
} else {
return {
isSuccess: false,
};
}
} catch (error) {
if (error instanceof BadRequestError) {
return {
isSuccess: false,
};
} else {
throw error;
}
}
// } catch (error) {
// if (error instanceof BadRequestError) {
// return {
// isSuccess: false,
// };
// } else {
// throw error;
// }
// }
};

export const addTakenLecture = async (lectureId: number) => {
Expand Down
2 changes: 1 addition & 1 deletion app/business/services/lecture/taken-lecture.query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export interface TakenLecturesResponse {
takenLectures: TakenLectureInfoResponse[];
}

interface TakenLectureInfoResponse {
export interface TakenLectureInfoResponse {
[index: string]: string | number;
id: number;
year: string;
Expand Down
13 changes: 11 additions & 2 deletions app/business/services/user/user.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ import {
SignInResponseSchema,
ValidateTokenResponseSchema,
ResetPasswordFormSchema,
isExpiredGradeUser,
} from './user.validation';
import { cookies } from 'next/headers';
import { isValidation } from '@/app/utils/zod/validation.util';
import { redirect } from 'next/navigation';
import { auth } from './user.query';
import { fetchUser } from './user.query';

function deleteCookies() {
cookies().delete('accessToken');
Expand Down Expand Up @@ -132,8 +133,16 @@ export async function authenticate(prevState: FormState, formData: FormData): Pr
}
}

const user = await fetchUser();
if (isExpiredGradeUser(user)) {
return {
isSuccess: true,
isFailure: false,
validationError: {},
message: '재업로드',
};
}
redirect('/my');

return {
isSuccess: true,
isFailure: false,
Expand Down
5 changes: 5 additions & 0 deletions app/business/services/user/user.validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,8 @@ export const SignUpFormSchema = z
export function isInitUser(x: UserInfoResponse | InitUserInfoResponse): x is InitUserInfoResponse {
return x.studentName === null;
}

export function isExpiredGradeUser(x: UserInfoResponse | InitUserInfoResponse): x is InitUserInfoResponse {
//return x.studentName !== null && x.takenCredit === 0 && x.totalCredit === 0;
return false;
}
2 changes: 1 addition & 1 deletion app/store/querys/lecture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const useFetchSearchLecture = () => {
const searchWord = useAtomValue(searchWordAtom);

return useSuspenseQuery<SearchedLectureInfoResponse[]>({
queryKey: [QUERY_KEY.SEARCH_LECTURE],
queryKey: [QUERY_KEY.SEARCH_LECTURE, searchWord.type, searchWord.keyword],
queryFn: () => {
return fetchSearchLectures(searchWord.type, searchWord.keyword as string);
},
Expand Down
1 change: 1 addition & 0 deletions app/store/stores/dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const initialState = {
[DIALOG_KEY.LECTURE_SEARCH]: false,
[DIALOG_KEY.USER_DELETE]: false,
[DIALOG_KEY.SIDE_NAVIGATION]: false,
[DIALOG_KEY.UPDATE_INSTRUCTION]: false,
};

const dialogAtom = atom(initialState);
Expand Down
24 changes: 23 additions & 1 deletion app/ui/lecture/lecture-search/lecture-search-result.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,22 @@ import List from '@/app/ui/view/molecule/list';
import Grid from '@/app/ui/view/molecule/grid';
import AddTakenLectureButton from '../taken-lecture/add-taken-lecture-button';
import { useFetchSearchLecture } from '@/app/store/querys/lecture';
import { useAtomValue } from 'jotai';
import { searchWordAtom } from '@/app/store/stores/search-word';

const emptyDataRender = (searchWord: string) => {
return (
<div className="flex flex-col items-center justify-center gap-4">
<div className="text-md font-medium text-gray-400 text-center whitespace-pre-wrap">
<span className="text-light-blue-7 text-lg font-semibold">{searchWord}</span> 에 대한 검색 결과가 없습니다.
</div>
</div>
);
};

export default function LectureSearchResult() {
const { data } = useFetchSearchLecture();
const searchWord = useAtomValue(searchWordAtom);

const renderAddActionButton = (item: SearchedLectureInfoResponse, taken: boolean) => {
return <AddTakenLectureButton lectureItem={item} isTaken={taken} />;
Expand All @@ -28,5 +41,14 @@ export default function LectureSearchResult() {
);
};

return <List data={data} render={render} isScrollList={true} />;
return (
<List
data={data}
render={render}
isScrollList={true}
emptyDataRender={() => {
return emptyDataRender(searchWord.keyword as string);
}}
/>
);
}
12 changes: 7 additions & 5 deletions app/ui/lecture/taken-lecture/delete-taken-lecture-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ import {
AlertDialogTitle,
AlertDialogTrigger,
} from '../../view/molecule/alert-dialog/alert-dialog';
import { TakenLectrueInfo } from '@/app/store/stores/custom-taken-lecture';

interface DeleteTakenLectureButtonProps {
lectureId: number;
onDelete: (lectureId: number) => void;
item: TakenLectrueInfo;
onDelete: (item: TakenLectrueInfo) => void;
}
export default function DeleteTakenLectureButton({ lectureId, onDelete }: DeleteTakenLectureButtonProps) {

export default function DeleteTakenLectureButton({ item, onDelete }: DeleteTakenLectureButtonProps) {
const [open, setOpen] = useState(false);
return (
<AlertDialog open={open} onOpenChange={setOpen}>
Expand All @@ -25,7 +27,7 @@ export default function DeleteTakenLectureButton({ lectureId, onDelete }: Delete
label="삭제"
variant="text"
size="default"
data-cy={`taken-lecture-delete-model-trigger-${lectureId}`}
data-cy={`taken-lecture-delete-model-trigger-${item.id}`}
data-testid="taken-lecture-delete-button"
/>
</div>
Expand All @@ -38,7 +40,7 @@ export default function DeleteTakenLectureButton({ lectureId, onDelete }: Delete
<AlertDialogCancel className="font-bold">취소</AlertDialogCancel>
<form
action={() => {
onDelete(lectureId);
onDelete(item);
}}
>
<Button
Expand Down
16 changes: 13 additions & 3 deletions app/ui/lecture/taken-lecture/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
import { fetchTakenLectures } from '@/app/business/services/lecture/taken-lecture.query';
import { fetchTakenLectures, TakenLectureInfoResponse } from '@/app/business/services/lecture/taken-lecture.query';
import TakenLectureList from './taken-lecture-list';
import TakenLectureLabel from './taken-lecture-label';
import TakenLectureAtomHydrator from '@/app/store/stores/taken-lecture-atom-hydrator';
import UpdateTakenLecture from './update-taken-lecture';

const processChapel = (takenLectures: TakenLectureInfoResponse[]) => {
return takenLectures.map((lecture) => {
return {
...lecture,
credit: lecture.lectureName === '채플' ? 0.5 : lecture.credit,
};
});
};
export default async function TakenLecture() {
const data = await fetchTakenLectures();
const takenLectures = processChapel(data.takenLectures);

return (
<div className="flex flex-col gap-2">
<TakenLectureAtomHydrator initialValue={data.takenLectures}>
<UpdateTakenLecture data={data.takenLectures}>
<TakenLectureAtomHydrator initialValue={takenLectures}>
<UpdateTakenLecture data={takenLectures}>
<TakenLectureLabel />
<TakenLectureList />
</UpdateTakenLecture>
Expand Down
18 changes: 11 additions & 7 deletions app/ui/lecture/taken-lecture/taken-lecture-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,26 @@ import { useToast } from '../../view/molecule/toast/use-toast';
import Responsive from '../../responsive';
import { TAKEN_LECTURE_TABLE_HEADER_INFO } from './taken-lecture-constant';
import { useTakenLecture } from '@/app/business/hooks/use-taken-lecture.hook';
import { TakenLectrueInfo } from '@/app/store/stores/custom-taken-lecture';

export default function TakenLectureList() {
const { optimisticLecture, deleteOptimisticLecture, deleteLecture } = useTakenLecture();

const { toast } = useToast();

const handleDeleteTakenLecture = async (lectureId: number) => {
deleteOptimisticLecture(lectureId);
const result = await deleteTakenLecture(lectureId);
const handleDeleteTakenLecture = async (item: TakenLectrueInfo) => {
deleteOptimisticLecture(item.lectureId);
const result = await deleteTakenLecture(item.id);
if (!result.isSuccess) {
return toast({
title: '과목 삭제에 실패했습니다',
title: `${item.lectureName} 삭제에 실패했습니다.`,
variant: 'destructive',
});
}
deleteLecture(lectureId);
deleteLecture(item.id);
toast({
title: `${item.lectureName} 과목을 삭제했습니다.`,
});
};

return (
Expand All @@ -30,8 +34,8 @@ export default function TakenLectureList() {
<Table
headerInfo={TAKEN_LECTURE_TABLE_HEADER_INFO}
data={optimisticLecture}
renderActionButton={(id: number) => (
<DeleteTakenLectureButton lectureId={id} onDelete={handleDeleteTakenLecture} />
renderActionButton={(item: TakenLectrueInfo) => (
<DeleteTakenLectureButton item={item} onDelete={handleDeleteTakenLecture} />
)}
/>
</Responsive>
Expand Down
24 changes: 16 additions & 8 deletions app/ui/user/sign-in-form/sign-in-form.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
'use client';
import UpdateInstruction from '@/app/(sub-page)/sign-in/components/update-instruction';
import Form from '../../view/molecule/form';
import { authenticate } from '@/app/business/services/user/user.command';
import { FormState } from '../../view/molecule/form/form-root';

export default function SignInForm() {
interface SignInForm {
onSuccess?: (formState?: FormState) => void;
}
export default function SignInForm({ onSuccess }: SignInForm) {
return (
<Form id="로그인" className="space-y-6" action={authenticate}>
<Form.TextInput required={true} label="아이디" id="authId" placeholder="아이디를 입력하세요" />
<Form.PasswordInput required={true} label="비밀번호" id="password" placeholder="비밀번호를 입력하세요" />
<div className="pt-6">
<Form.SubmitButton label="로그인" position="center" variant="primary" />
</div>
</Form>
<>
<Form id="로그인" className="space-y-6" action={authenticate} onSuccess={onSuccess}>
<Form.TextInput required={true} label="아이디" id="authId" placeholder="아이디를 입력하세요" />
<Form.PasswordInput required={true} label="비밀번호" id="password" placeholder="비밀번호를 입력하세요" />
<div className="pt-6">
<Form.SubmitButton label="로그인" position="center" variant="primary" />
</div>
</Form>
<UpdateInstruction />
</>
);
}
2 changes: 1 addition & 1 deletion app/ui/view/atom/button/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const ButtonVariants = cva(`flex justify-center items-center`, {
dark: 'bg-dark rounded-[100px] text-white border-0 hover:bg-dark-hover',
secondary: 'bg-white rounded-[100px] border-solid border-[1px] border-gray-6 hover:bg-white-hover',
text: 'font-medium text-slate-400 text-sm hover:text-slate-600',
list: 'py-1 px-3 bg-blue-500 rounded-[7px] text-white leading-5 font-medium text-base hover:bg-blue-500',
list: 'py-1 px-3 bg-blue-500 rounded-[7px] text-white leading-5 font-medium text-base hover:bg-blue-600',
},
size: {
default: '',
Expand Down
Loading

0 comments on commit 4f123d7

Please sign in to comment.