diff --git a/src/api/README.md b/src/api/README.md index 300cccb..0937d4a 100644 --- a/src/api/README.md +++ b/src/api/README.md @@ -101,19 +101,19 @@ const MemberList = async () => { } ``` -## User Store +## Member Store ```tsx const MyPage = () => { - const { user } = useUserStore(); + const { member } = useMemberStore(); return (

My Info

- Name: {user.name} - Email: {user.email} + Name: {member.name} + Email: {member.email}
); diff --git a/src/api/domain/Activity.ts b/src/api/domain/Activity.ts index a6c7aaa..dc8a1a3 100644 --- a/src/api/domain/Activity.ts +++ b/src/api/domain/Activity.ts @@ -1,7 +1,44 @@ -import { WinkApiRequest } from '@/api'; +import { + Project, + ProjectAdmin, + Social, + SocialAdmin, + Study, + StudyAdmin, + WinkApiRequest, +} from '@/api'; export class Activity { constructor(private readonly request: WinkApiRequest) {} -} -////////////////////////////////////////////////////////////////////////// + private readonly project: Project = new Project(this.request); + private readonly projectAdmin: ProjectAdmin = new ProjectAdmin(this.request); + private readonly study: Study = new Study(this.request); + private readonly studyAdmin: StudyAdmin = new StudyAdmin(this.request); + private readonly social: Social = new Social(this.request); + private readonly socialAdmin: SocialAdmin = new SocialAdmin(this.request); + + public get Project() { + return this.project; + } + + public get ProjectAdmin() { + return this.projectAdmin; + } + + public get Study() { + return this.study; + } + + public get StudyAdmin() { + return this.studyAdmin; + } + + public get Social() { + return this.social; + } + + public get SocialAdmin() { + return this.socialAdmin; + } +} diff --git a/src/api/domain/Auth.ts b/src/api/domain/Auth.ts index cd91011..1ab834e 100644 --- a/src/api/domain/Auth.ts +++ b/src/api/domain/Auth.ts @@ -1,4 +1,4 @@ -import { MyInfoLinks, RoleString, WinkApiRequest } from '@/api'; +import { MemberType, WinkApiRequest } from '@/api'; export class Auth { constructor(private readonly request: WinkApiRequest) {} @@ -72,15 +72,5 @@ export interface VerifyCodeResponseDto { } export interface MyInfoResponseDto { - memberId: string; - createdAt: Date; - updatedAt: Date; - name: string; - studentId: string; - email: string; - avatar: string | null; - description: string | null; - link: MyInfoLinks; - role: RoleString | null; - fee: boolean; + member: MemberType; } diff --git a/src/api/domain/Member.ts b/src/api/domain/Member.ts index 915a2e1..f6e554c 100644 --- a/src/api/domain/Member.ts +++ b/src/api/domain/Member.ts @@ -91,7 +91,7 @@ export interface UpdateMyPasswordRequestDto { ////////////////////////////////////////////////////////////////////////// export interface EachGetMembersResponseDto { - memberId: string; + _id: string; createdAt: Date; updatedAt: Date; name: string; @@ -116,7 +116,7 @@ export interface GetMembersForAdminResponseDto { } export interface EachGetWaitingMembersResponseDto { - memberId: string; + _id: string; name: string; studentId: string; } @@ -152,4 +152,4 @@ export enum Role { export type RoleString = keyof typeof Role; -export type User = MyInfoResponseDto; +export type MemberType = MyInfoResponseDto; diff --git a/src/api/domain/activity/Project.ts b/src/api/domain/activity/Project.ts new file mode 100644 index 0000000..84c788c --- /dev/null +++ b/src/api/domain/activity/Project.ts @@ -0,0 +1,94 @@ +import { MemberType, WinkApiRequest } from '@/api'; + +export class Project { + constructor(private readonly request: WinkApiRequest) {} + + public async getProject(data: GetProjectRequestDto): Promise { + return this.request.get('/activity/project/detail', data); + } + + public async getProjectsPage(): Promise { + return this.request.get('/activity/project/max'); + } + + public async getProjects(data: GetProjectsRequestDto): Promise { + return this.request.get('/activity/project', data); + } +} + +export class ProjectAdmin { + constructor(private readonly request: WinkApiRequest) {} + + public async createProject(data: CreateProjectRequestDto): Promise { + return this.request.put('/admin/activity/project', data); + } + + public async updateProject(data: UpdateProjectRequestDto): Promise { + return this.request.patch('/admin/activity/project', data); + } + + public async deleteProject(data: DeleteProjectRequestDto): Promise { + return this.request.delete('/admin/activity/project', data); + } +} + +////////////////////////////////////////////////////////////////////////// + +export interface CreateProjectRequestDto { + title: string; + content: string; + tags: string[]; + image: string; +} + +export interface DeleteProjectRequestDto { + projectId: string; +} + +export interface GetProjectRequestDto { + projectId: string; +} + +export interface GetProjectsRequestDto { + page: number; +} + +export interface UpdateProjectRequestDto { + projectId: string; + title: string; + content: string; + tags: string[]; + image: string; +} + +////////////////////////////////////////////////////////////////////////// + +export interface CreateProjectResponseDto { + project: ProjectType; +} + +export interface GetProjectResponseDto { + project: ProjectType; +} + +export interface GetProjectsResponseDto { + projects: ProjectType[]; +} + +export interface GetProjectsPageResponseDto { + page: number; +} + +////////////////////////////////////////////////////////////////////////// + +export interface ProjectType { + _id: string; + createdAt: Date; + updatedAt: Date; + type: 'Project' | 'Study' | 'Social'; + author: MemberType; + title: string; + content: string; + tags: string[]; + image: string; +} diff --git a/src/api/domain/activity/Social.ts b/src/api/domain/activity/Social.ts new file mode 100644 index 0000000..4f14387 --- /dev/null +++ b/src/api/domain/activity/Social.ts @@ -0,0 +1,80 @@ +import { WinkApiRequest } from '@/api'; + +export class Social { + constructor(private readonly request: WinkApiRequest) {} + + public async getSocial(data: GetSocialRequestDto): Promise { + return this.request.get('/activity/social/detail', data); + } + + public async getSocials(): Promise { + return this.request.get('/activity/social'); + } +} + +export class SocialAdmin { + constructor(private readonly request: WinkApiRequest) {} + + public async createSocial(data: CreateSocialRequestDto): Promise { + return this.request.put('/admin/activity/social', data); + } + + public async updateSocial(data: UpdateSocialRequestDto): Promise { + return this.request.patch('/admin/activity/social', data); + } + + public async deleteSocial(data: DeleteSocialRequestDto): Promise { + return this.request.delete('/admin/activity/social', data); + } +} + +////////////////////////////////////////////////////////////////////////// + +export interface CreateSocialRequestDto { + title: string; + contents: Content[]; +} + +export interface DeleteSocialRequestDto { + socialId: string; +} + +export interface GetSocialRequestDto { + socialId: string; +} + +export interface UpdateSocialRequestDto { + socialId: string; + title: string; + contents: Content[]; +} + +////////////////////////////////////////////////////////////////////////// + +export interface CreateSocialResponseDto { + social: SocialType; +} + +export interface GetSocialResponseDto { + social: SocialType; +} + +export interface GetSocialsResponseDto { + socials: SocialType[]; +} + +////////////////////////////////////////////////////////////////////////// + +export interface SocialType { + _id: string; + createdAt: Date; + updatedAt: Date; + type: 'Project' | 'Study' | 'Social'; + title: string; + contents: Content[]; +} + +export interface Content { + content: string; + image: string; +} diff --git a/src/api/domain/activity/Study.ts b/src/api/domain/activity/Study.ts new file mode 100644 index 0000000..b60c335 --- /dev/null +++ b/src/api/domain/activity/Study.ts @@ -0,0 +1,109 @@ +import { WinkApiRequest } from '@/api'; + +export class Study { + constructor(private readonly request: WinkApiRequest) {} + + public async getCategories(): Promise { + return this.request.get('/activity/study/category'); + } + + public async getStudiesPage(): Promise { + return this.request.get('/activity/study/max'); + } + + public async getStudies(page: number): Promise { + return this.request.get(`/activity/study/${page}`); + } +} + +export class StudyAdmin { + constructor(private readonly request: WinkApiRequest) {} + + public async createCategory(data: CreateCategoryRequestDto): Promise { + return this.request.put('/admin/activity/study/category', data); + } + + public async updateCategory(data: UpdateCategoryRequestDto): Promise { + return this.request.patch('/admin/activity/study/category', data); + } + + public async deleteCategory(data: DeleteCategoryRequestDto): Promise { + return this.request.delete('/admin/activity/study/category', data); + } + + public async createStudy(data: CreateStudyRequestDto): Promise { + return this.request.put('/admin/activity/study', data); + } + + public async deleteStudy(data: DeleteStudyRequestDto): Promise { + return this.request.delete('/admin/activity/study', data); + } +} + +////////////////////////////////////////////////////////////////////////// + +export interface CreateCategoryRequestDto { + category: string; +} + +export interface CreateStudyRequestDto { + link: string; +} + +export interface DeleteCategoryRequestDto { + categoryId: string; +} + +export interface DeleteStudyRequestDto { + studyId: string; +} + +export interface UpdateCategoryRequestDto { + categoryId: string; + category: string; +} + +////////////////////////////////////////////////////////////////////////// + +export interface CreateCategoryResponseDto { + category: Category; +} + +export interface CreateStudyResponseDto { + study: StudyType; +} + +export interface GetCategoriesResponseDto { + categories: Category[]; +} + +export interface GetStudiesResponse { + studies: StudyType[]; +} + +export interface GetStudiesPageResponse { + page: number; +} + +////////////////////////////////////////////////////////////////////////// + +export interface StudyType { + _id: string; + createdAt: Date; + updatedAt: Date; + type: 'Project' | 'Study' | 'Social'; + title: string; + content: string; + author: string; + image: string; + link: string; + uploadedAt: Date; + category: Category; +} + +export interface Category { + _id: string; + createdAt: Date; + updatedAt: Date; + name: string; +} diff --git a/src/api/domain/index.ts b/src/api/domain/index.ts index 75dddd1..f58708e 100644 --- a/src/api/domain/index.ts +++ b/src/api/domain/index.ts @@ -1,3 +1,7 @@ export * from './Auth'; export * from './Member'; export * from './Activity'; + +export * from './activity/Project'; +export * from './activity/Study'; +export * from './activity/Social'; diff --git a/src/api/request/WinkApiRequest.ts b/src/api/request/WinkApiRequest.ts index c7bf40e..4547cf3 100644 --- a/src/api/request/WinkApiRequest.ts +++ b/src/api/request/WinkApiRequest.ts @@ -1,9 +1,9 @@ import Cookies from 'js-cookie'; import { toast } from 'react-toastify'; -import { RefreshResponseDto, User } from '@/api'; +import { RefreshResponseDto, MyInfoResponseDto } from '@/api'; -import { useUserStore, useApplicationState } from '@/store'; +import { useMemberStore, useApplicationState } from '@/store'; interface WinkRawApiResponse { code: number; @@ -38,8 +38,8 @@ export class WinkApiRequest { const response = await fetch(`${this.baseUrl}/api${url}`, { ...options, headers: { - 'Content-Type': 'application/json', Authorization: `Bearer ${this.accessToken}`, + ...(options.headers || {}), }, }); @@ -78,33 +78,33 @@ export class WinkApiRequest { } } - public async get(url: string): Promise { - return this.request(url, { method: 'GET' }); + public async get(url: string, body?: object | FormData): Promise { + return this.request(url, { method: 'GET', body: body && this.generateBody(body) }); } - public async post(url: string, body?: object): Promise { + public async post(url: string, body?: object | FormData): Promise { return this.request(url, { method: 'POST', - body: body && JSON.stringify(body), + body: body && this.generateBody(body), }); } - public async put(url: string, body?: object): Promise { + public async put(url: string, body?: object | FormData): Promise { return this.request(url, { method: 'PUT', - body: body && JSON.stringify(body), + body: body && this.generateBody(body), }); } - public async patch(url: string, body?: object): Promise { + public async patch(url: string, body?: object | FormData): Promise { return this.request(url, { method: 'PATCH', - body: body && JSON.stringify(body), + body: body && this.generateBody(body), }); } - public async delete(url: string): Promise { - return this.request(url, { method: 'DELETE' }); + public async delete(url: string, body?: object | FormData): Promise { + return this.request(url, { method: 'DELETE', body: body && this.generateBody(body) }); } public setToken(accessToken: string, refreshToken: string) { @@ -118,7 +118,7 @@ export class WinkApiRequest { Cookies.set('accessToken', accessToken, { expires: (1 / 24 / 60) * 15 }); Cookies.set('refreshToken', refreshToken, { expires: 30 }); - this.updateUser(); + this.updateMember(); } public removeToken() { @@ -132,21 +132,32 @@ export class WinkApiRequest { Cookies.remove('accessToken'); Cookies.remove('refreshToken'); - this.updateUser(); + this.updateMember(); } - private updateUser() { + private updateMember() { if (!this.accessToken) { - useUserStore.setState({ user: null }); + useMemberStore.setState({ member: null }); return; } - this.get('/auth/me').then((user) => { - useUserStore.setState({ user: user as User }); + (async () => { + const response: MyInfoResponseDto = await this.get('/auth/me'); + const { member } = response; + + useMemberStore.setState({ member }); if (!useApplicationState.getState().loaded) { useApplicationState.setState({ loaded: true }); } - }); + })(); + } + + private generateBody(body: object | FormData): string | FormData { + if (body instanceof FormData) { + return body; + } + + return JSON.stringify(body); } } diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 1caae1d..6177f9e 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -9,12 +9,12 @@ import { usePathname } from 'next/navigation'; import { WinkApi } from '@/api'; -import { useUserStore } from '@/store'; +import { useMemberStore } from '@/store'; import logo from '@/public/logo.png'; export const Header: React.FC = () => { - const { user } = useUserStore(); + const { member } = useMemberStore(); const pathName = usePathname(); @@ -41,10 +41,10 @@ export const Header: React.FC = () => { useLink: true, }, { - title: user ? 'logout' : 'login', - href: user ? '#' : '/login', + title: member ? 'logout' : 'login', + href: member ? '#' : '/login', mobileHide: true, - useLink: !user, + useLink: !member, }, ]; diff --git a/src/components/WebInKookmin.tsx b/src/components/WebInKookmin.tsx index 3ea3717..ffb9fa9 100644 --- a/src/components/WebInKookmin.tsx +++ b/src/components/WebInKookmin.tsx @@ -2,26 +2,26 @@ import React from 'react'; export const WebInKookmin: React.FC = () => { const text = [ - { text: 'W', color: 'wink-200' }, - { text: 'E', color: 'wink-50' }, - { text: 'B', color: 'wink-50' }, - { text: ' ', color: 'white' }, - { text: 'I', color: 'wink-200' }, - { text: 'N', color: 'wink-200' }, - { text: ' ', color: 'white' }, - { text: 'K', color: 'wink-200' }, - { text: 'O', color: 'wink-50' }, - { text: 'O', color: 'wink-50' }, - { text: 'K', color: 'wink-50' }, - { text: 'M', color: 'wink-50' }, - { text: 'I', color: 'wink-50' }, - { text: 'N', color: 'wink-50' }, + { text: 'W', color: 'text-wink-200' }, + { text: 'E', color: 'text-wink-50' }, + { text: 'B', color: 'text-wink-50' }, + { text: ' ', color: 'text-white' }, + { text: 'I', color: 'text-wink-200' }, + { text: 'N', color: 'text-wink-200' }, + { text: ' ', color: 'text-white' }, + { text: 'K', color: 'text-wink-200' }, + { text: 'O', color: 'text-wink-50' }, + { text: 'O', color: 'text-wink-50' }, + { text: 'K', color: 'text-wink-50' }, + { text: 'M', color: 'text-wink-50' }, + { text: 'I', color: 'text-wink-50' }, + { text: 'N', color: 'text-wink-50' }, ]; return (
{text.map(({ text, color }, i) => ( - + {text} ))} diff --git a/src/store/index.ts b/src/store/index.ts index 0da1a94..49c975d 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -1,2 +1,2 @@ -export * from './useUserStore'; +export * from './useMemberStore'; export * from './useApplicationState'; diff --git a/src/store/useMemberStore.ts b/src/store/useMemberStore.ts new file mode 100644 index 0000000..4a30163 --- /dev/null +++ b/src/store/useMemberStore.ts @@ -0,0 +1,16 @@ +import { create } from 'zustand'; + +import { MemberType } from '@/api'; + +interface MemberState { + member: MemberType | null; + setMember: (member: MemberType | null) => void; +} + +export const useMemberStore = create((set) => ({ + member: null, + setMember: (member: MemberType | null) => + set(() => ({ + member, + })), +})); diff --git a/src/store/useUserStore.ts b/src/store/useUserStore.ts deleted file mode 100644 index 2dd6434..0000000 --- a/src/store/useUserStore.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { create } from 'zustand'; - -import { User } from '@/api'; - -interface UserState { - user: User | null; - setUser: (user: User | null) => void; -} - -export const useUserStore = create((set) => ({ - user: null, - setUser: (user: User | null) => - set(() => ({ - user, - })), -}));