Skip to content

Commit

Permalink
Merge pull request #42 from teamViNO/feature-050
Browse files Browse the repository at this point in the history
Feature 050
  • Loading branch information
whistleJs authored Feb 8, 2024
2 parents 7fe1ba2 + ae8b071 commit e49f4f6
Show file tree
Hide file tree
Showing 8 changed files with 167 additions and 24 deletions.
36 changes: 29 additions & 7 deletions src/apis/user.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
import { APIResponse } from '@/models/config/axios';
import { CheckEmailRequest, CheckEmailResponse, JoinRequest, JoinResponse, LoginRequest, LoginResponse } from '@/models/user';
import { AlarmResponse } from '@/models/alarm';
import {
CheckEmailRequest,
CheckEmailResponse,
JoinRequest,
JoinResponse,
LoginRequest,
LoginResponse,
} from '@/models/user';
import {
AlarmResponse,
ConfirmAlarmRequest,
DeleteAlarmRequest,
DeleteAlarmResponse,
} from '@/models/alarm';

import axios from './config/instance';

Expand All @@ -10,10 +22,23 @@ export const loginAPI = (data: LoginRequest) => {
return axios.post<APIResponse<LoginResponse>>(PREFIX + '/login', data);
};

export const getAlarm = () => {
export const getAlarmAPI = () => {
return axios.get<APIResponse<AlarmResponse>>(PREFIX + '/alarm');
};

export const deleteSelectAlarmAPI = (data: DeleteAlarmRequest) => {
return axios.delete<APIResponse<DeleteAlarmResponse>>(
PREFIX + '/alarm/selectDelete',
{
data,
},
);
};

export const confirmSelectAlarmAPI = (data: ConfirmAlarmRequest) => {
return axios.patch(PREFIX + '/alarm/selectedConfirm', data);
};

export const checkEmailAPI = (data: CheckEmailRequest) => {
return axios.post<APIResponse<CheckEmailResponse>>(
PREFIX + '/checkemail',
Expand All @@ -22,8 +47,5 @@ export const checkEmailAPI = (data: CheckEmailRequest) => {
};

export const joinAPI = (data: JoinRequest) => {
return axios.post<APIResponse<JoinResponse>>(
PREFIX + '/join',
data,
);
return axios.post<APIResponse<JoinResponse>>(PREFIX + '/join', data);
};
24 changes: 20 additions & 4 deletions src/components/layout/header/alarm/AlarmItem.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { IAlarm } from '@/models/alarm';

import CheckIcon from '@/assets/icons/check.svg?react';
import CheckIcon from '@/assets/icons/checked.svg?react';
import EmptyFileImage from '@/assets/empty-file.png';
import FileImage from '@/assets/file.png';
import FileReadImage from '@/assets/file-read.png';
Expand All @@ -11,9 +11,12 @@ import { diffTime } from '@/utils/date';

type Props = {
alarm: IAlarm;
selectIdList: number[];
onUpdateSelectIdList: (list: number[]) => void;
};

const AlarmItem = ({ alarm }: Props) => {
const AlarmItem = ({ alarm, selectIdList, onUpdateSelectIdList }: Props) => {
const isSelected = selectIdList.indexOf(alarm.alarm_id) > -1;
const type = alarm.type === 'video' ? '영상 변환' : '환영인사';

const image = () => {
Expand All @@ -37,6 +40,14 @@ const AlarmItem = ({ alarm }: Props) => {
return `${second}초`;
};

const handleClickRemoveButton = () => {
if (selectIdList.indexOf(alarm.alarm_id) < 0) {
onUpdateSelectIdList([...selectIdList, alarm.alarm_id]);
} else {
onUpdateSelectIdList(selectIdList.filter((id) => id !== alarm.alarm_id));
}
};

return (
<Container className={`${alarm.is_confirm && 'read'}`}>
<div className="top">
Expand All @@ -48,8 +59,13 @@ const AlarmItem = ({ alarm }: Props) => {
<span className="time">{time()}</span>
</div>

<button className="remove-button">
<CheckIcon width={24} height={24} />
<button
className={`remove-button ${selectIdList.length && 'show'} ${
isSelected && 'selected'
}`}
onClick={handleClickRemoveButton}
>
<CheckIcon width={16} height={16} />
</button>
</div>

Expand Down
57 changes: 53 additions & 4 deletions src/components/layout/header/alarm/AlarmList.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import { useState } from 'react';

import { deleteSelectAlarmAPI, confirmSelectAlarmAPI } from '@/apis/user';

import { IAlarm } from '@/models/alarm';

import * as AlarmListStyle from '@/styles/layout/header/alarm/AlarmList.style';
Expand All @@ -7,24 +11,69 @@ import AlarmItem from './AlarmItem';

type Props = {
alarmList: IAlarm[];
onRefresh: () => void;
};

const AlarmList = ({ alarmList }: Props) => {
const AlarmList = ({ alarmList, onRefresh }: Props) => {
const [selectIdList, setSelectIdList] = useState<number[]>([]);
const count = alarmList.filter((item) => !item.is_confirm).length;

const handleRemove = async (alarms: number[]) => {
try {
await deleteSelectAlarmAPI({ alarms });

setSelectIdList([]);
onRefresh();
} catch (e) {
console.error(e);
}
};

const handleClickRemoveAll = () => {
handleRemove(alarmList.map((i) => i.alarm_id));
};

const handleClickRemoveSelected = () => {
handleRemove(selectIdList);
};

const handleClickReadSelected = async () => {
try {
await confirmSelectAlarmAPI({ alarms: selectIdList });

setSelectIdList([]);
onRefresh();
} catch (e) {
console.error(e);
}
};

return (
<AlarmListStyle.Layout>
<AlarmListStyle.Container>
<AlarmListStyle.Container style={{ gap: selectIdList.length ? 20 : 36 }}>
<AlarmListStyle.NoticeWrap>
<span style={theme.typography.Subheader3}>읽지 않은 알림</span>

<div className={`notice-count ${count && 'active'}`}>{count}</div>
</AlarmListStyle.NoticeWrap>

{count ? (
{Boolean(selectIdList.length) && (
<AlarmListStyle.NoticeToolWrap>
<span onClick={handleClickRemoveAll}>모두 삭제</span>
<span onClick={handleClickReadSelected}>읽음</span>
<span onClick={handleClickRemoveSelected}>삭제</span>
</AlarmListStyle.NoticeToolWrap>
)}

{alarmList.length ? (
<div style={{ padding: '0 28px', maxHeight: 480, overflowY: 'auto' }}>
{alarmList.map((alarm) => (
<AlarmItem key={alarm.alarm_id} alarm={alarm} />
<AlarmItem
key={alarm.alarm_id}
alarm={alarm}
selectIdList={selectIdList}
onUpdateSelectIdList={setSelectIdList}
/>
))}
</div>
) : (
Expand Down
6 changes: 3 additions & 3 deletions src/components/layout/header/alarm/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useEffect, useState } from 'react';

import { getAlarm } from '@/apis/user';
import { getAlarmAPI } from '@/apis/user';

import NotifyOffIcon from '@/assets/icons/notify-off.svg?react';
import NotifyOnIcon from '@/assets/icons/notify-on.svg?react';
Expand All @@ -24,7 +24,7 @@ const Alarm = ({ isDark }: Props) => {
const hasNotReadAlarm = alarmList.find((item) => !item.is_confirm);

const callAPI = async () => {
const { alarms } = (await getAlarm()).data.result;
const { alarms } = (await getAlarmAPI()).data.result;

setAlarmList(alarms);
};
Expand All @@ -46,7 +46,7 @@ const Alarm = ({ isDark }: Props) => {
)}
</HeaderStyle.Button>

{isOpen && <AlarmList alarmList={alarmList} />}
{isOpen && <AlarmList alarmList={alarmList} onRefresh={callAPI} />}
</div>
);
};
Expand Down
1 change: 0 additions & 1 deletion src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,5 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
<RecoilRoot>
<App />
</RecoilRoot>
,
</React.StrictMode>,
);
12 changes: 12 additions & 0 deletions src/models/alarm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,15 @@ export interface IAlarm {
export interface AlarmResponse {
alarms: IAlarm[];
}

export interface DeleteAlarmRequest {
alarms: number[];
}

export interface DeleteAlarmResponse {
status: string;
}

export interface ConfirmAlarmRequest {
alarms: number[];
}
40 changes: 36 additions & 4 deletions src/styles/layout/header/alarm/AlarmItem.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,33 @@ export const Container = styled.div`
width: 100%;
&:first-of-type {
padding: 0 0 28px;
padding-top: 0;
}
&:last-of-type {
padding-bottom: 0;
}
&:not(:last-of-type) {
border-bottom: solid 1px ${(props) => props.theme.color.gray200};
}
&:hover button.remove-button {
opacity: 1 !important;
visibility: visible !important;
}
&.read {
& div.color {
background-color: ${(props) => props.theme.color.gray300};
background-color: ${(props) => props.theme.color.gray300} !important;
}
& span.type {
color: ${(props) => props.theme.color.gray400};
color: ${(props) => props.theme.color.gray400} !important;
}
& div.content {
color: ${(props) => props.theme.color.gray300};
color: ${(props) => props.theme.color.gray300} !important;
}
}
Expand Down Expand Up @@ -59,10 +68,33 @@ export const Container = styled.div`
}
& button.remove-button {
display: flex;
align-items: center;
justify-content: center;
padding: 0;
width: 24px;
height: 24px;
border: none;
outline: none;
border-radius: 50%;
background-color: ${(props) => props.theme.color.gray200};
opacity: 0;
visibility: hidden;
transition: 0.1s;
cursor: pointer;
&.show {
opacity: 1;
visibility: visible;
}
&.selected {
background-color: ${(props) => props.theme.color.gray500};
& path {
stroke: ${(props) => props.theme.color.gray200};
}
}
& path {
stroke: ${(props) => props.theme.color.gray300};
Expand Down
15 changes: 14 additions & 1 deletion src/styles/layout/header/alarm/AlarmList.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ export const Container = styled.div`
padding: 36px 0;
display: flex;
flex-direction: column;
gap: 36px;
z-index: 99;
box-shadow: 4px 4px 30px 0 rgba(0, 0, 0, 0.16);
`;
Expand Down Expand Up @@ -52,3 +51,17 @@ export const NoticeAbsenceMessage = styled.div`
text-align: center;
color: ${theme.color.gray300};
`;

export const NoticeToolWrap = styled.div`
padding: 0 28px;
display: flex;
align-items: center;
justify-content: flex-end;
gap: 12px;
& > span {
color: ${(props) => props.theme.color.gray400};
cursor: pointer;
${(props) => props.theme.typography.Caption1};
}
`;

0 comments on commit e49f4f6

Please sign in to comment.