diff --git a/apps/client/src/features/session/chatting/chatting.slice.ts b/apps/client/src/features/session/chatting/chatting.slice.ts new file mode 100644 index 0000000..32c7026 --- /dev/null +++ b/apps/client/src/features/session/chatting/chatting.slice.ts @@ -0,0 +1,21 @@ +import { StateCreator } from 'zustand'; + +import { Chat } from '@/features/session/chatting'; + +export interface ChattingSlice { + chatting: Chat[]; + resetChatting: () => void; + addChatting: (chat: Chat) => void; +} + +export const createChattingSlice: StateCreator< + ChattingSlice, + [], + [], + ChattingSlice +> = (set) => ({ + chatting: [], + resetChatting: () => set({ chatting: [] }), + addChatting: (chat) => + set((state) => ({ chatting: [...state.chatting, chat] })), +}); diff --git a/apps/client/src/features/session/chatting/chatting.type.ts b/apps/client/src/features/session/chatting/chatting.type.ts new file mode 100644 index 0000000..18053b6 --- /dev/null +++ b/apps/client/src/features/session/chatting/chatting.type.ts @@ -0,0 +1,8 @@ +export interface Chat { + id: string; + body: string; + user: { + token: string; + nickname: string; + }; +} diff --git a/apps/client/src/features/session/chatting/index.ts b/apps/client/src/features/session/chatting/index.ts new file mode 100644 index 0000000..d309070 --- /dev/null +++ b/apps/client/src/features/session/chatting/index.ts @@ -0,0 +1,2 @@ +export * from './chatting.type'; +export * from './chatting.slice'; diff --git a/apps/client/src/features/session/index.ts b/apps/client/src/features/session/index.ts new file mode 100644 index 0000000..6aa6401 --- /dev/null +++ b/apps/client/src/features/session/index.ts @@ -0,0 +1 @@ +export * from './session.store'; diff --git a/apps/client/src/features/session/qa/index.ts b/apps/client/src/features/session/qa/index.ts new file mode 100644 index 0000000..b854fba --- /dev/null +++ b/apps/client/src/features/session/qa/index.ts @@ -0,0 +1,2 @@ +export * from './qa.type'; +export * from './qa.slice'; diff --git a/apps/client/src/features/session/qa/qa.slice.ts b/apps/client/src/features/session/qa/qa.slice.ts new file mode 100644 index 0000000..edc5b9f --- /dev/null +++ b/apps/client/src/features/session/qa/qa.slice.ts @@ -0,0 +1,81 @@ +import { StateCreator } from 'zustand/index'; + +import { Question, Reply } from '@/features/session/qa/qa.type'; + +export interface QASlice { + questions: Question[]; + resetQuestions: () => void; + addQuestion: (question: Question) => void; + updateQuestion: (question: Question) => void; + removeQuestion: (question: Question) => void; + upvoteQuestion: (question: Question) => void; + addReply: (reply: Reply) => void; + updateReply: (reply: Reply) => void; + removeReply: (reply: Reply) => void; + upvoteReply: (reply: Reply) => void; +} + +export const createQASlice: StateCreator = (set) => ({ + questions: [], + resetQuestions: () => set({ questions: [] }), + addQuestion: (question) => + set((state) => ({ ...state, questions: [...state.questions, question] })), + updateQuestion: (question) => + set((state) => ({ + ...state, + questions: state.questions.map((q) => + q.id === question.id ? question : q, + ), + })), + removeQuestion: (question) => + set((state) => ({ + ...state, + questions: state.questions.filter((q) => q.id !== question.id), + })), + upvoteQuestion: (question) => + set((state) => ({ + ...state, + questions: state.questions.map((q) => + q.id === question.id ? { ...q, upvotes: q.upvotes + 1 } : q, + ), + })), + addReply: (reply) => + set((state) => ({ + ...state, + questions: state.questions.map((q) => + q.id === reply.questionId + ? { ...q, replies: [...q.replies, reply] } + : q, + ), + })), + updateReply: (reply) => + set((state) => ({ + ...state, + questions: state.questions.map((q) => + q.id === reply.questionId + ? { + ...q, + replies: q.replies.map((r) => (r.id === reply.id ? reply : r)), + } + : q, + ), + })), + removeReply: (reply) => + set((state) => ({ + ...state, + questions: state.questions.map((q) => ({ + ...q, + replies: q.replies.filter((r) => r.id !== reply.id), + })), + })), + upvoteReply: (reply) => + set((state) => ({ + ...state, + questions: state.questions.map((q) => ({ + ...q, + replies: q.replies.map((r) => + r.id === reply.id ? { ...r, upvotes: r.upvotes + 1 } : r, + ), + })), + })), +}); diff --git a/apps/client/src/features/session/qa/qa.type.ts b/apps/client/src/features/session/qa/qa.type.ts new file mode 100644 index 0000000..e3db7f7 --- /dev/null +++ b/apps/client/src/features/session/qa/qa.type.ts @@ -0,0 +1,28 @@ +import { Session } from '@/features/session'; + +export interface Question { + id: number; + sessionId: Session['id']; + body: string; + closed: boolean; + pinned: boolean; + upvotes: number; + replies: Reply[]; + user: { + token: string; + nickname: string; + }; + createdAt: string; +} + +export interface Reply { + id: number; + questionId: Question['id']; + body: string; + user: { + token: string; + nickname: string; + }; + upvotes: number; + createdAt: string; +} diff --git a/apps/client/src/features/session/session.slice.ts b/apps/client/src/features/session/session.slice.ts new file mode 100644 index 0000000..c34f988 --- /dev/null +++ b/apps/client/src/features/session/session.slice.ts @@ -0,0 +1,26 @@ +import { StateCreator } from 'zustand/index'; + +import { ChattingSlice } from '@/features/session/chatting'; +import { QASlice } from '@/features/session/qa'; +import { Session } from '@/features/session/session.type'; + +export interface SessionSlice { + session?: Session; + reset: () => void; + setSession: (session: Session) => void; +} + +export const createSessionSlice: StateCreator< + SessionSlice & QASlice & ChattingSlice, + [], + [], + SessionSlice +> = (set, get) => ({ + session: undefined, + reset: () => { + get().resetQuestions(); + get().resetChatting(); + set({ session: undefined }); + }, + setSession: (session) => set({ session }), +}); diff --git a/apps/client/src/features/session/session.store.ts b/apps/client/src/features/session/session.store.ts new file mode 100644 index 0000000..04bb249 --- /dev/null +++ b/apps/client/src/features/session/session.store.ts @@ -0,0 +1,19 @@ +import { create } from 'zustand'; + +import { + ChattingSlice, + createChattingSlice, +} from '@/features/session/chatting'; +import { createQASlice, QASlice } from '@/features/session/qa'; +import { + createSessionSlice, + SessionSlice, +} from '@/features/session/session.slice'; + +export type SessionStore = SessionSlice & QASlice & ChattingSlice; + +export const useSessionStore = create()((...a) => ({ + ...createQASlice(...a), + ...createChattingSlice(...a), + ...createSessionSlice(...a), +})); diff --git a/apps/client/src/features/session/session.type.ts b/apps/client/src/features/session/session.type.ts new file mode 100644 index 0000000..cd1013a --- /dev/null +++ b/apps/client/src/features/session/session.type.ts @@ -0,0 +1,6 @@ +export interface Session { + id: string; + title: string; + expiredAt: string; + createdAt: string; +}