Skip to content
26 changes: 22 additions & 4 deletions services/admin/src/apis/votes/index.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,40 @@
import { instance } from '..';
import { CreateVoteRequest } from './request';
import { CreateVoteOptionRequest, CreateVoteRequest } from './request';
import { VoteListResponse } from './response';

const router = '/votes';
const exemplaryRouter = '/candidate-list';

export const getVoteList = async () => {
const { data } = await instance.get<VoteListResponse>(`${router}`);
return data;
};

export const createVote = async (body: CreateVoteRequest) => {
instance.post(`${router}`, body);
await instance.post(`${router}`, body);
};

export const patchVote = async (body: CreateVoteRequest, votingId: string) => {
instance.patch(`${router}/${votingId}`, body);
await instance.patch(`${router}/${votingId}`, body);
};

export const deleteVote = async (votingId: string) => {
instance.delete(`${router}/${votingId}`);
await instance.delete(`${router}/${votingId}`);
};

export const createVoteOption = async (body: CreateVoteOptionRequest) => {
const { data } = await instance.post(`${router}/options`, body);
return data;
};

export const getVoteResult = async (votingTopicId: string) => {
const { data } = await instance.get(`${router}/result/${votingTopicId}`);
return data;
};

export const getExemplaryStudents = async (requestDate: string) => {
const { data } = await instance.get(exemplaryRouter, {
params: { requestDate },
});
return data.students;
};
11 changes: 11 additions & 0 deletions services/admin/src/apis/votes/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,14 @@ export interface CreateVoteRequest {
start_time: string;
end_time: string;
}
export interface CreateVoteOptionRequest {
voting_topic_id: string;
option_name: string;
}

export interface Student {
id: string;
student_gcn: string;
name: string;
profile_image_url: string;
}
9 changes: 9 additions & 0 deletions services/admin/src/apis/votes/response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,12 @@ export interface VoteListResponse {
vote_type: string;
}[];
}

export interface VoteResultResponse {
voting_topic_id: string;
options: {
id: string;
name: string;
votes: number;
}[];
}
9 changes: 8 additions & 1 deletion services/admin/src/components/modals/CreateVoteModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ interface VoteProps {
topic_name?: string;
description?: string;
vote_date?: string;
votingId?: string;
}

export const CreateVoteModal = ({
Expand Down Expand Up @@ -149,7 +150,13 @@ export const CreateVoteModal = ({

return (
<>
{isOpen && <VotePopup mode="create" onClose={onVotePopupClose} />}
{isOpen && (
<VotePopup
mode="create"
onClose={onVotePopupClose}
votingId={surveyId}
/>
)}
{!isOpen && (
<Modal
close={closeModal}
Expand Down
31 changes: 14 additions & 17 deletions services/admin/src/components/modals/VotePopup.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,39 @@
import React, { useState } from 'react';
import { useState } from 'react';
import styled from 'styled-components';
import Delete from '../../assets/delete.svg';
import { font } from '@team-aliens/design-system/dist/styles/theme/font';
import { Button, Modal } from '@team-aliens/design-system';
import { color } from '@team-aliens/design-system/dist/styles/theme/color';
import { FullListPopup } from './FullListPopup';
import { useCreateVoteOption } from '@/hooks/useVoteApi';

interface PropsType {
mode: string;
votingId: string;
onClose: () => void;
}

export const VotePopup = ({ mode, onClose }: PropsType) => {
const [items, setItems] = useState(
mode === 'edit' ? [{ value: '김치' }, { value: '파전' }] : [],
);
export const VotePopup = ({ mode, votingId, onClose }: PropsType) => {
const [items, setItems] = useState<{ value: string }[]>([]);
const [isFull, setIsFull] = useState<boolean>(false);
const [inputValue, setInputValue] = useState('');

const { mutate: addVoteOption } = useCreateVoteOption();

const handleAddItem = () => {
if (inputValue) {
if (items.length >= 50) {
setIsFull(true);
} else {
addVoteOption({ voting_topic_id: votingId, option_name: inputValue });
setItems([...items, { value: inputValue }]);
setInputValue('');
}
}
};

const handleDeleteItem = (index) => {
const newItems = items.filter((_, i) => i !== index);
setItems(newItems);
const handleDeleteItem = (index: number) => {
setItems(items.filter((_, i) => i !== index));
};

const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
Expand All @@ -40,19 +42,15 @@ export const VotePopup = ({ mode, onClose }: PropsType) => {
}
};

const onFullListPopUpClose = () => {
setIsFull(false);
};

return (
<>
<Modal
close={() => {}}
close={onClose}
buttonList={[
<Button kind="outline" onClick={onClose}>
<Button key="previous" kind="outline" onClick={onClose}>
이전
</Button>,
<Button>확인</Button>,
<Button key="confirm">확인</Button>,
]}
width="1150px"
>
Expand All @@ -70,7 +68,6 @@ export const VotePopup = ({ mode, onClose }: PropsType) => {
</button>
</li>
))}

<li>
<input
type="text"
Expand All @@ -84,7 +81,7 @@ export const VotePopup = ({ mode, onClose }: PropsType) => {
</_Contents>
</_Wrapper>
</Modal>
{isFull && <FullListPopup onClose={onFullListPopUpClose} />}
{isFull && <FullListPopup onClose={() => setIsFull(false)} />}
</>
);
};
Expand Down
47 changes: 41 additions & 6 deletions services/admin/src/hooks/useVoteApi.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
import { createVote, deleteVote, getVoteList, patchVote } from '@/apis/votes';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import {
createVote,
deleteVote,
getVoteList,
patchVote,
createVoteOption,
getVoteResult,
} from '@/apis/votes';
import { useToast } from './useToast';
import { CreateVoteRequest } from '@/apis/votes/request';
import { useModal } from './useModal';
import {
CreateVoteRequest,
CreateVoteOptionRequest,
} from '@/apis/votes/request';

export const useVoteList = () => {
return useQuery(['getVoteList'], () => getVoteList());
return useQuery(['getVoteList'], getVoteList);
};

export const useDeleteVote = () => {
const queryClient = useQueryClient();
const { toastDispatch } = useToast();

return useMutation((voteId: string) => deleteVote(voteId), {
return useMutation(deleteVote, {
onSuccess: () => {
toastDispatch({
actionType: 'APPEND_TOAST',
Expand All @@ -28,7 +37,7 @@ export const useWriteVote = () => {
const { toastDispatch } = useToast();
const queryClient = useQueryClient();

return useMutation((content: CreateVoteRequest) => createVote(content), {
return useMutation(createVote, {
onSuccess: () => {
toastDispatch({
actionType: 'APPEND_TOAST',
Expand Down Expand Up @@ -59,3 +68,29 @@ export const usePatchVote = () => {
},
);
};

export const useCreateVoteOption = () => {
const { toastDispatch } = useToast();
const queryClient = useQueryClient();

return useMutation(createVoteOption, {
onSuccess: () => {
toastDispatch({
actionType: 'APPEND_TOAST',
toastType: 'SUCCESS',
message: '투표 항목이 추가되었습니다.',
});
queryClient.invalidateQueries(['getVoteList']);
},
});
};

export const useVoteResult = (votingTopicId: string) => {
return useQuery(
['getVoteResult', votingTopicId],
() => getVoteResult(votingTopicId),
{
enabled: !!votingTopicId,
},
);
};