From d6a5154aad55dc79a36cdfe1b22da629d0965eaf Mon Sep 17 00:00:00 2001
From: Yumin Cho <dbals081216@gmail.com>
Date: Sat, 18 May 2024 21:39:55 +0900
Subject: [PATCH 1/2] feat: add detailed end time on enabled terminated agenda
 card

---
 .../AgendaCard/TerminatedAgendaCard.tsx       | 31 ++++++++++++++-----
 1 file changed, 23 insertions(+), 8 deletions(-)

diff --git a/packages/web/src/components/molecules/AgendaCard/TerminatedAgendaCard.tsx b/packages/web/src/components/molecules/AgendaCard/TerminatedAgendaCard.tsx
index db175807..f23369ba 100644
--- a/packages/web/src/components/molecules/AgendaCard/TerminatedAgendaCard.tsx
+++ b/packages/web/src/components/molecules/AgendaCard/TerminatedAgendaCard.tsx
@@ -8,8 +8,21 @@ import { OptionVoteResult } from "@biseo/web/components/molecules/OptionVoteResu
 import { VoteResult } from "@biseo/web/components/molecules/VoteResult";
 import { VoteDetail } from "@biseo/web/components/molecules/VoteDetail";
 import { VoteParticipate } from "@biseo/web/components/molecules/VoteParticipate";
-import { align, column, gap, justify, row, text, w } from "@biseo/web/styles";
-import { formatDateSimple } from "@biseo/web/utils/format";
+import {
+  align,
+  center,
+  column,
+  gap,
+  justify,
+  row,
+  text,
+  w,
+} from "@biseo/web/styles";
+import {
+  formatDate,
+  formatDateSimple,
+  formatTime,
+} from "@biseo/web/utils/format";
 
 const agendaTags = {
   public: true,
@@ -43,18 +56,20 @@ export const TerminatedAgendaCard: React.FC<Props> = ({ agenda }) => {
       {enabled ? (
         <div css={[column, gap(15), w("fill")]}>
           <div css={[column, gap(2)]}>
-            <div css={[row, justify.between, align.center]}>
-              <h1 css={[text.title2, text.black]}>{agenda.title}</h1>
-              <p css={[text.subtitle, text.gray400]}>
-                {formatDateSimple(agenda.endAt)}
-              </p>
-            </div>
+            <h1 css={[text.title2, text.black]}>{agenda.title}</h1>
             <p css={[text.subtitle, text.gray500]}>{agenda.content}</p>
           </div>
           <div>
             <p css={[text.body, text.blue600]}>{agenda.resolution}</p>
           </div>
           <Divider />
+          <div css={[row, center, justify.between, text.subtitle, text.black]}>
+            <span>νˆ¬ν‘œ μΌμ‹œ</span>
+            <span css={[row, gap(4)]}>
+              <span>{formatDate(agenda.endAt)}</span>
+              <span>{formatTime(agenda.endAt)}</span>
+            </span>
+          </div>
           <VoteParticipate
             voted={agenda.voters.voted}
             total={agenda.voters.total}

From 6079f864b79d730750be8aaf2aecd6e3e2041139 Mon Sep 17 00:00:00 2001
From: Yumin Cho <dbals081216@gmail.com>
Date: Sat, 18 May 2024 21:52:21 +0900
Subject: [PATCH 2/2] feat: get endAt on termination to update admin state

---
 packages/api/src/listener/admin.agenda.ts     | 14 +++++++++-----
 packages/interface/src/admin/agenda/client.ts |  1 +
 packages/interface/src/admin/agenda/server.ts |  1 +
 packages/web/src/services/admin-agenda.ts     |  9 +++++----
 4 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/packages/api/src/listener/admin.agenda.ts b/packages/api/src/listener/admin.agenda.ts
index c674d68e..22e0b2b9 100644
--- a/packages/api/src/listener/admin.agenda.ts
+++ b/packages/api/src/listener/admin.agenda.ts
@@ -38,7 +38,9 @@ router.on(
 
         const startNotice = await createNotice(ongoingAgenda, user);
         io.emit("chat.received", startNotice);
-        break;
+
+        io.to("admin").emit("admin.agenda.statusUpdated", req);
+        return {};
       }
       case "terminated": {
         const terminatedAgenda = await terminateAgenda(req.id, user);
@@ -46,14 +48,16 @@ router.on(
 
         const terminateNotice = await createNotice(terminatedAgenda, user);
         io.emit("chat.received", terminateNotice);
-        break;
+
+        io.to("admin").emit("admin.agenda.statusUpdated", {
+          ...req,
+          endAt: terminatedAgenda.endAt,
+        });
+        return {};
       }
       default:
         return {};
     }
-
-    io.to("admin").emit("admin.agenda.statusUpdated", req);
-    return {};
   },
 );
 
diff --git a/packages/interface/src/admin/agenda/client.ts b/packages/interface/src/admin/agenda/client.ts
index 9abd3adb..08f8c6f8 100644
--- a/packages/interface/src/admin/agenda/client.ts
+++ b/packages/interface/src/admin/agenda/client.ts
@@ -28,6 +28,7 @@ export type RetrieveAllCb = z.infer<typeof RetrieveAllCb>;
 export const StatusUpdate = z.object({
   id: z.number(),
   status: AgendaStatus,
+  endAt: z.string().optional(),
 });
 export type StatusUpdate = z.infer<typeof StatusUpdate>;
 export const StatusUpdateCb = z.object({});
diff --git a/packages/interface/src/admin/agenda/server.ts b/packages/interface/src/admin/agenda/server.ts
index 28c281a7..7e8bec9e 100644
--- a/packages/interface/src/admin/agenda/server.ts
+++ b/packages/interface/src/admin/agenda/server.ts
@@ -18,6 +18,7 @@ export type Created = z.infer<typeof Created>;
 export const StatusUpdated = z.object({
   id: z.number(),
   status: AgendaStatus,
+  endAt: z.string().optional(),
 });
 export type StatusUpdated = z.infer<typeof StatusUpdated>;
 
diff --git a/packages/web/src/services/admin-agenda.ts b/packages/web/src/services/admin-agenda.ts
index 3c6abe8a..5a5995af 100644
--- a/packages/web/src/services/admin-agenda.ts
+++ b/packages/web/src/services/admin-agenda.ts
@@ -11,7 +11,7 @@ interface AdminAgendaState {
   adminAgendas: AdminAgenda[];
   createAgenda: (agenda: AdminAgendaCreate) => void;
   retrieveAll: () => void;
-  statusUpdate: (id: number, status: AgendaStatus) => void;
+  statusUpdate: (id: number, status: AgendaStatus, endAt?: string) => void;
   updateAgenda: (agenda: AdminAgendaUpdate) => void;
   deleteAgenda: (id: number) => void;
   remindAgenda: (id: number) => void;
@@ -39,11 +39,12 @@ export const useAdminAgenda = create<AdminAgendaState>(set => ({
       // TODO: handle error
     }
   },
-  statusUpdate: async (id, status) => {
+  statusUpdate: async (id, status, endAt) => {
     try {
       await socket.emitAsync("admin.agenda.statusUpdate", {
         id,
         status,
+        endAt,
       });
     } catch {
       // TODO: handle error
@@ -81,11 +82,11 @@ socket.on("admin.agenda.created", adminAgenda => {
   }));
 });
 
-socket.on("admin.agenda.statusUpdated", ({ id, status }) => {
+socket.on("admin.agenda.statusUpdated", ({ id, status, endAt }) => {
   useAdminAgenda.setState(state => {
     const newAdminAgendas: AdminAgenda[] = state.adminAgendas.map(agenda => {
       if (agenda.id === id) {
-        return { ...agenda, status };
+        return { ...agenda, status, endAt: endAt || "" };
       }
       return agenda;
     });