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

Use suspense query error/#120 #121

Merged
merged 11 commits into from
Jun 30, 2024
3 changes: 2 additions & 1 deletion app/business/services/auth.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use server';
import { cookies } from 'next/headers';

export const getToken = (): string | undefined => {
export const getToken = async (): Promise<string | undefined> => {
return cookies().get('accessToken')?.value;
};
// server action은 asyncλ₯Ό 써야함
106 changes: 55 additions & 51 deletions app/business/services/lecture/taken-lecture.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { httpErrorHandler } from '@/app/utils/http/http-error-handler';
import { BadRequestError } from '@/app/utils/http/http-error';
import { revalidateTag } from 'next/cache';
import { TAG } from '@/app/utils/http/tag';
import { cookies } from 'next/headers';
import { getToken } from '../auth';

export const registerUserGrade = async (prevState: FormState, formData: FormData) => {
const parsingText = await parsePDFtoText(formData);
Expand Down Expand Up @@ -43,60 +45,62 @@ export const parsePDFtoText = async (formData: FormData) => {
};

export const deleteTakenLecture = async (lectureId: number) => {
try {
const response = await fetch(API_PATH.takenLectures, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ lectureId }),
});
const result = await response.json();
httpErrorHandler(response, result);
} catch (error) {
if (error instanceof BadRequestError) {
return {
isSuccess: false,
};
} else {
throw error;
}
// 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,
};
}
revalidateTag(TAG.GET_TAKEN_LECTURES);
return {
isSuccess: true,
};
// } catch (error) {
// if (error instanceof BadRequestError) {
// return {
// isSuccess: false,
// };
// } else {
// throw error;
// }
// }
};

export const addTakenLecture = async (lectureId: number) => {
try {
const response = await fetch(API_PATH.takenLectures, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ lectureId }),
});
const result = await response.json();
httpErrorHandler(response, result);
} catch (error) {
if (error instanceof BadRequestError) {
return {
isSuccess: false,
isFailure: true,
validationError: {},
message: 'κ³Όλͺ© 좔가에 μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€',
};
} else {
throw error;
}
const token = await getToken();
const response = await fetch(API_PATH.takenLectures, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({ lectureId }),
});
// delete taken lectureκ³Ό λΉ„μŠ·ν•œ 이유둜 μ½”λ“œ μˆ˜μ •
if (response.ok) {
revalidateTag(TAG.GET_TAKEN_LECTURES);
return {
isSuccess: true,
isFailure: false,
validationError: {},
message: 'κ³Όλͺ© 좔가에 μ„±κ³΅ν–ˆμŠ΅λ‹ˆλ‹€',
};
} else {
return {
isSuccess: false,
isFailure: true,
validationError: {},
message: 'κ³Όλͺ© 좔가에 μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€',
};
}

revalidateTag(TAG.GET_TAKEN_LECTURES);
return {
isSuccess: true,
isFailure: false,
validationError: {},
message: 'κ³Όλͺ© 좔가에 μ„±κ³΅ν–ˆμŠ΅λ‹ˆλ‹€',
};
};
4 changes: 2 additions & 2 deletions app/business/services/lecture/taken-lecture.query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import { cookies } from 'next/headers';

export interface TakenLecturesResponse {
totalCredit: number;
takenLectures: TakenLectrueInfoResponse[];
takenLectures: TakenLectureInfoResponse[];
}

interface TakenLectrueInfoResponse {
interface TakenLectureInfoResponse {
[index: string]: string | number;
id: number;
year: string;
Expand Down
3 changes: 1 addition & 2 deletions app/business/services/user/user.query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export async function auth(): Promise<InitUserInfoResponse | UserInfoResponse |

export async function fetchUser(): Promise<InitUserInfoResponse | UserInfoResponse> {
try {
const response = await fetch(`${API_PATH.user}`, {
const response = await fetch(`${API_PATH.user}/me`, {
headers: {
Authorization: `Bearer ${cookies().get('accessToken')?.value}`,
},
Expand All @@ -29,7 +29,6 @@ export async function fetchUser(): Promise<InitUserInfoResponse | UserInfoRespon
const result = await response.json();

httpErrorHandler(response, result);

if (isValidation(result, UserInfoResponseSchema || InitUserInfoResponseSchema)) {
return result;
} else {
Expand Down
4 changes: 2 additions & 2 deletions app/business/services/user/user.validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { UserInfoResponse, InitUserInfoResponse } from './user.type';
export const UserInfoResponseSchema = z.object({
studentNumber: z.string(),
studentName: z.string(),
completionDivision: z.array(
completeDivision: z.array(
z.object({
majorType: z.enum(['PRIMARY', 'DUAL', 'SUB']),
major: z.string(),
Expand All @@ -18,7 +18,7 @@ export const UserInfoResponseSchema = z.object({
export const InitUserInfoResponseSchema = z.object({
studentNumber: z.string(),
studentName: z.null(),
completionDivision: z.null(),
completeDivision: z.null(),
totalCredit: z.null(),
takenCredit: z.null(),
graduated: z.null(),
Expand Down
80 changes: 42 additions & 38 deletions app/mocks/data.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export const takenLectures = JSON.parse(`{
export const userInfo = JSON.parse(`{
"studentNumber": "60181666",
"studentName": "μž₯μ§„μš±",
"completionDivision" : [
"completeDivision" : [
{
"majorType" : "PRIMARY",
"major": "λ””μ§€ν„Έμ½˜ν…μΈ λ””μžμΈν•™κ³Ό"
Expand Down Expand Up @@ -279,41 +279,45 @@ export const credits = JSON.parse(`[
}
]`);

export const searchLectures = JSON.parse(`{
"lectures": [
{
"id": 1,
"lectureCode": "KMA02106",
"name": "μ˜μ–΄1",
"credit": 2,
"isTaken" : false
},
{
"id": 2,
"lectureCode": "KMA02106",
"name": "μ˜μ–΄2",
"credit": 2,
"isTaken" : true
},
{
"id": 3,
"lectureCode": "KMA02136",
"name": "μ˜μ–΄λ¬΄μ—­μ΄λ‘ ",
"credit": 3,
"isTaken" : false
},
{
"id": 1,
"lectureCode": "KMA02106",
"name": "μ˜μ–΄νšŒν™”3",
"credit": 1,
"isTaken" : false
},
export const searchLectures = [
{
"id": 1,
"lectureCode": "KMA02106",
"name": "μ˜μ–΄νšŒν™”4",
"credit": 2,
"isTaken" : true
}]
}`);
id: 1,
lectureCode: 'KMA02106',
name: 'μ˜μ–΄1',
credit: 2,
taken: false,
revoked: true,
},
{
id: 2,
lectureCode: 'KMA02106',
name: 'μ˜μ–΄2',
credit: 2,
taken: true,
revoked: false,
},
{
id: 3,
lectureCode: 'KMA02136',
name: 'μ˜μ–΄λ¬΄μ—­μ΄λ‘ ',
credit: 3,
taken: false,
revoked: false,
},
{
id: 4,
lectureCode: 'KMA02106',
name: 'μ˜μ–΄νšŒν™”3',
credit: 1,
taken: false,
revoked: false,
},
{
id: 6,
lectureCode: 'KMA02106',
name: 'μ˜μ–΄νšŒν™”4',
credit: 2,
taken: true,
revoked: false,
},
];
10 changes: 5 additions & 5 deletions app/mocks/db.mock.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { SearchLecturesResponse } from '../store/querys/lecture';
import { TakenLecturesResponse } from '../business/services/lecture/taken-lecture.query';
import { CreditResponse, ResultCategoryDetailResponse } from '../store/querys/result';
import {
Expand All @@ -8,20 +7,21 @@ import {
InitUserInfoResponse,
} from '../business/services/user/user.type';
import { takenLectures, credits, searchLectures, userInfo, users, resultCategoryDetailInfo } from './data.mock';
import { SearchedLectureInfoResponse } from '../store/querys/lecture';

interface MockDatabaseState {
takenLectures: TakenLecturesResponse;
resultCategoryDetailInfo: ResultCategoryDetailResponse;
credits: CreditResponse[];
users: SignUpRequestBody[];
searchLectures: SearchLecturesResponse;
searchLectures: SearchedLectureInfoResponse[];
userInfo: UserInfoResponse;
}

type MockDatabaseAction = {
reset: () => void;
getTakenLectures: () => TakenLecturesResponse;
getSearchLectures: () => SearchLecturesResponse;
getSearchLectures: () => SearchedLectureInfoResponse[];
addTakenLecture: (lectureId: number) => boolean;
deleteTakenLecture: (lectureId: number) => boolean;
createUser: (user: SignUpRequestBody) => boolean;
Expand Down Expand Up @@ -49,7 +49,7 @@ export const mockDatabase: MockDatabaseAction = {
return false;
},
addTakenLecture: (lectureId) => {
const lecture = mockDatabaseStore.searchLectures.lectures.find((lecture) => lecture.id === lectureId);
const lecture = mockDatabaseStore.searchLectures.find((lecture) => lecture.id === lectureId);
if (!lecture) {
return false;
}
Expand Down Expand Up @@ -85,7 +85,7 @@ export const mockDatabase: MockDatabaseAction = {
return {
studentNumber: '',
studentName: null,
completionDivision: null,
completeDivision: null,
totalCredit: null,
takenCredit: null,
graduated: null,
Expand Down
13 changes: 5 additions & 8 deletions app/store/querys/lecture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { API_PATH } from '@/app/business/api-path';
import { getToken } from '@/app/business/services/auth';
import { LectureInfoResponse } from './result';

export type SearchedLectureInfoResponse = LectureInfoResponse & { isTaken: boolean };
export type SearchedLectureInfoResponse = LectureInfoResponse & { taken: boolean; revoked: boolean };

export const useFetchSearchLecture = () => {
const searchWord = useAtomValue(searchWordAtom);
Expand All @@ -20,15 +20,12 @@ export const useFetchSearchLecture = () => {
});
};

export interface SearchLecturesResponse {
lectures: SearchedLectureInfoResponse[];
}

export const fetchSearchLectures = async (type: string, keyword: string) => {
const response = await axios<SearchLecturesResponse>(`${API_PATH.lectures}?type=${type}&&keyword=${keyword}`, {
const token = await getToken();
const response = await axios<SearchedLectureInfoResponse[]>(`${API_PATH.lectures}?type=${type}&&keyword=${keyword}`, {
headers: {
Authorization: `Bearer ${getToken()}`,
Authorization: `Bearer ${token}`,
},
});
return response.data.lectures;
return response.data;
};
2 changes: 1 addition & 1 deletion app/ui/lecture/lecture-search/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export default function LectureSearch() {
const searchable = searchWord.keyword && searchWord.keyword.length > 1;

return (
<div className="bg-white w-full h-[500px] sm:h-[400px] z-[10] flex justify-center" data-testid="lecture-search">
<div className="bg-white w-full h-[520px] sm:h-[420px] z-[10] flex justify-center" data-testid="lecture-search">
<div className="w-[800px] mx-auto my-7 flex flex-col gap-10 sm:gap-6">
<LectureSearchBar />
{searchable ? (
Expand Down
3 changes: 2 additions & 1 deletion app/ui/lecture/lecture-search/lecture-search-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,15 @@ export default function LectureSearchBar() {
<Select.Item value="lectureCode" placeholder="κ³Όλͺ©μ½”λ“œ" />
</Select>
</div>
<div className="w-[60%] sm:w-[40%] flex justify-between">
<div className="w-[60%] sm:w-[40%] flex justify-between flex-col gap-1">
<TextInput
data-cy="search-lecture-input"
placeholder="검색어λ₯Ό μž…λ ₯ν•΄μ£Όμ„Έμš”"
icon={MagnifyingGlassIcon}
onValueChange={handleDebounceKeywordSearch}
data-testid="lecture-search-input"
/>
<div className="text-zinc-400 text-xs text-end">β€» νšŒμƒ‰μœΌλ‘œ ν‘œκΈ°λœ κ³Όλͺ©μ€ 폐강과λͺ©μž…λ‹ˆλ‹€</div>
</div>
</div>
);
Expand Down
Loading
Loading