Skip to content

Commit

Permalink
feat(fe): add chat and Q&A management slices with session store (#28)
Browse files Browse the repository at this point in the history
* feat: add chatting slice and types for chat management

* feat: add QA slice and types for question and reply management

* feat: add session management slice and store

* feat: add reset functionality to chatting and QA slices, and integrate into session slice

* feat: update QA slice to use Question and Reply objects for removal and upvoting
  • Loading branch information
cjeongmin authored Nov 7, 2024
1 parent 7df3a6f commit 3288a52
Show file tree
Hide file tree
Showing 10 changed files with 194 additions and 0 deletions.
21 changes: 21 additions & 0 deletions apps/client/src/features/session/chatting/chatting.slice.ts
Original file line number Diff line number Diff line change
@@ -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] })),
});
8 changes: 8 additions & 0 deletions apps/client/src/features/session/chatting/chatting.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export interface Chat {
id: string;
body: string;
user: {
token: string;
nickname: string;
};
}
2 changes: 2 additions & 0 deletions apps/client/src/features/session/chatting/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './chatting.type';
export * from './chatting.slice';
1 change: 1 addition & 0 deletions apps/client/src/features/session/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './session.store';
2 changes: 2 additions & 0 deletions apps/client/src/features/session/qa/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './qa.type';
export * from './qa.slice';
81 changes: 81 additions & 0 deletions apps/client/src/features/session/qa/qa.slice.ts
Original file line number Diff line number Diff line change
@@ -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<QASlice, [], [], QASlice> = (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,
),
})),
})),
});
28 changes: 28 additions & 0 deletions apps/client/src/features/session/qa/qa.type.ts
Original file line number Diff line number Diff line change
@@ -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;
}
26 changes: 26 additions & 0 deletions apps/client/src/features/session/session.slice.ts
Original file line number Diff line number Diff line change
@@ -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 }),
});
19 changes: 19 additions & 0 deletions apps/client/src/features/session/session.store.ts
Original file line number Diff line number Diff line change
@@ -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<SessionStore>()((...a) => ({
...createQASlice(...a),
...createChattingSlice(...a),
...createSessionSlice(...a),
}));
6 changes: 6 additions & 0 deletions apps/client/src/features/session/session.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface Session {
id: string;
title: string;
expiredAt: string;
createdAt: string;
}

0 comments on commit 3288a52

Please sign in to comment.