Skip to content

Commit

Permalink
Merge pull request #310 from mash-up-kr/develop
Browse files Browse the repository at this point in the history
Main Release/1.9.0
  • Loading branch information
kikiyeom authored Aug 23, 2024
2 parents 22cfb4e + 435aeea commit 95e83bc
Show file tree
Hide file tree
Showing 8 changed files with 209 additions and 18 deletions.
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
import React, { useMemo } from 'react';
import { useFieldArray, useFormContext } from 'react-hook-form';
import { useRecoilValue } from 'recoil';
import { Button, DatePickerField, InputField, RadioButtonField, SelectField } from '@/components';
import {
Button,
DatePickerField,
InputField,
RadioButtonField,
SelectField,
Textarea,
} from '@/components';
import { InputSize } from '@/components/common/Input/Input.component';
import * as Styled from './ScheduleTemplate.styled';
import { $generations } from '@/store';
import { $generations, $profile, $teams } from '@/store';
import { SelectOption } from '@/components/common/Select/Select.component';
import { SessionTemplate } from '../SessionTemplate';
import Plus from '@/assets/svg/plus-20.svg';
import { EventCreateRequest } from '@/types';
import { LocationType, ScheduleFormValues } from '@/utils';
import { LocationType, ScheduleFormValues, ScheduleType } from '@/utils';
import { useScript } from '@/hooks';

const DEFAULT_SESSION: EventCreateRequest = {
Expand All @@ -26,8 +33,11 @@ const ScheduleTemplate = () => {
const { register, control, formState, getValues, watch, setValue } =
useFormContext<ScheduleFormValues>();
const generations = useRecoilValue($generations);
const [position] = useRecoilValue($profile);
const teams = useRecoilValue($teams);

const locationType = watch('locationType');
const scheduleType = watch('scheduleType');

const { fields, append, remove } = useFieldArray({
name: 'sessions',
Expand All @@ -46,6 +56,23 @@ const ScheduleTemplate = () => {
const defaultOption = generationOptions.find(
(option) => option.value === getValues('generationNumber')?.toString(),
);

const generationPlatformOptions = teams.map(({ name }) => ({
value: name.toUpperCase(),
label: name,
}));

const getTeamSelectOptions = () => {
const myTeamOptionObject = generationPlatformOptions.find(({ value }) => value === position);
return myTeamOptionObject ? [myTeamOptionObject] : generationPlatformOptions;
};

const teamSelectOptions = getTeamSelectOptions();

const defaultPlatformOption = generationPlatformOptions.find(
(option) => option.value === getValues('schedulePlatformType'),
);

const handleClickAddressSearch = () => {
new window.daum.Postcode({
async oncomplete(data: { address: string }) {
Expand Down Expand Up @@ -96,6 +123,37 @@ const ScheduleTemplate = () => {
isFullWidth
{...register('generationNumber', { required: true })}
/>
<div>
<Styled.InputLabel htmlFor="location">
<span>구분</span>
<Styled.RequiredDot />
</Styled.InputLabel>
<Styled.RadioButtonGroup>
<RadioButtonField
label="플랫폼"
required
value={ScheduleType.PLATFORM}
{...register('scheduleType', { required: true })}
/>
<RadioButtonField
label="전체"
required
value={ScheduleType.ALL}
{...register('scheduleType', { required: true })}
/>
</Styled.RadioButtonGroup>
{scheduleType === ScheduleType.PLATFORM && (
<SelectField
size="md"
options={teamSelectOptions}
defaultValue={defaultPlatformOption}
required
{...register('schedulePlatformType', {
required: scheduleType === ScheduleType.PLATFORM,
})}
/>
)}
</div>
<DatePickerField
label="스케줄 일시"
$size="md"
Expand Down Expand Up @@ -146,6 +204,7 @@ const ScheduleTemplate = () => {
</Styled.LocationWrapper>
)}
</div>
<Textarea label="공지" {...register('notice')} />
</Styled.ScheduleContent>
<Styled.SessionContent>
<Styled.Title>세션 정보</Styled.Title>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import React, { useMemo } from 'react';
import { ScheduleStatus, ValueOf } from '@/types';

import * as Styled from './ScheduleInfoList.styled';
import { formatDate, getScheduleStatusText } from '@/utils';
import { formatDate, getScheduleStatusText, getScheduleType, SchedulePlatformType } from '@/utils';

interface ScheduleInfoListProps {
generationNumber: number;
scheduleType: ValueOf<typeof SchedulePlatformType>;
name: string;
createdAt: string;
startedAt: string;
Expand All @@ -15,16 +16,19 @@ interface ScheduleInfoListProps {
roadAddress?: string | null;
detailAddress: string;
};
notice: string | null;
}

const ScheduleInfoList = ({
name,
generationNumber,
scheduleType,
startedAt,
createdAt,
publishedAt,
status,
location,
notice,
}: ScheduleInfoListProps) => {
const scheduleInfoListItem = useMemo(() => {
return [
Expand All @@ -36,6 +40,10 @@ const ScheduleInfoList = ({
label: '기수',
value: `${generationNumber}기`,
},
{
label: '구분',
value: getScheduleType(scheduleType),
},
{
label: '스케줄 일시',
value: formatDate(startedAt, 'YYYY년 M월 D일 A hh시 mm분'),
Expand All @@ -53,6 +61,10 @@ const ScheduleInfoList = ({
location.detailAddress ? `, ${location.detailAddress}` : ''
}`,
},
{
label: '공지',
value: notice || '-',
},
{
label: '배포 일시',
value: formatDate(publishedAt, 'YYYY년 M월 D일 A hh시 mm분'),
Expand All @@ -62,7 +74,18 @@ const ScheduleInfoList = ({
value: getScheduleStatusText(status),
},
];
}, [createdAt, generationNumber, name, publishedAt, startedAt, status, location]);
}, [
createdAt,
generationNumber,
location.detailAddress,
location.roadAddress,
name,
notice,
publishedAt,
scheduleType,
startedAt,
status,
]);

return (
<Styled.ScheduleInfoList>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import * as Styled from './TeamNavigationTabs.styled';

const TEAMS = ['All', 'Design', 'Android', 'iOS', 'Web', 'Node', 'Spring'];

const TeamNavigationTabs = () => {
interface TeamNavigationTabsProps {
allAltText?: string;
}

const TeamNavigationTabs = ({ allAltText }: TeamNavigationTabsProps) => {
const [searchParams, setSearchParams] = useSearchParams();

const handleClickTab = (teamParam: string) => {
Expand All @@ -23,17 +27,18 @@ const TeamNavigationTabs = () => {
const teamParam = team === 'All' ? '' : team.toUpperCase();
const active =
team === 'All' ? !searchParams.has('team') : searchParams.get('team') === teamParam;

const isAllAltText = team === 'All' && !!allAltText;
return (
<Styled.Tab
key={index}
role="link"
aria-label={`${team} tab`}
aria-current={active}
active={active}
isAllAltText={isAllAltText}
onClick={() => handleClickTab(teamParam)}
>
{team}
{isAllAltText ? allAltText : team}
</Styled.Tab>
);
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import styled from '@emotion/styled';

interface StyledNavigationItemProps {
active: boolean;
isAllAltText?: boolean;
}

export const Tabs = styled.nav`
Expand All @@ -15,13 +16,13 @@ export const Tabs = styled.nav`
`;

export const Tab = styled.button<StyledNavigationItemProps>`
${({ theme, active }) => css`
${({ theme, active, isAllAltText }) => css`
${theme.fonts.regular16};
display: flex;
align-items: center;
justify-content: center;
width: 8rem;
width: ${isAllAltText ? '12rem' : '8rem'};
height: 4rem;
color: ${active ? theme.colors.purple70 : theme.colors.gray50};
letter-spacing: -0.08rem;
Expand Down
4 changes: 4 additions & 0 deletions src/pages/ScheduleDetail/ScheduleDetail.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,15 @@ const ScheduleDetail = () => {

const {
name,
scheduleType,
generationNumber,
startedAt,
createdAt,
publishedAt,
status,
eventList: sessionList,
location,
notice,
} = useRecoilValue($scheduleDetail({ scheduleId: scheduleId ?? '' }));

const isPublished = status === ScheduleStatus.PUBLIC;
Expand Down Expand Up @@ -143,12 +145,14 @@ const ScheduleDetail = () => {
<h3>스케줄 정보</h3>
<ScheduleInfoList
name={name}
scheduleType={scheduleType}
generationNumber={generationNumber}
startedAt={startedAt}
createdAt={createdAt}
publishedAt={publishedAt}
status={status}
location={location}
notice={notice}
/>
</Styled.Content>
<Styled.Content>
Expand Down
42 changes: 35 additions & 7 deletions src/pages/ScheduleList/ScheduleList.page.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,50 @@
import React, { useEffect, useMemo } from 'react';
import React, { useEffect, useMemo, MouseEvent } from 'react';
import { useLocation, useSearchParams } from 'react-router-dom';
import { useRecoilStateLoadable, useRecoilValue } from 'recoil';
import { BottomCTA, Button, Link, Pagination, SearchOptionBar, Table } from '@/components';
import {
BottomCTA,
Button,
Link,
Pagination,
SearchOptionBar,
Table,
TeamNavigationTabs,
} from '@/components';
import * as Styled from './ScheduleList.styled';
import { TableColumn } from '@/components/common/Table/Table.component';
import { ScheduleRequest, ScheduleResponse, ScheduleStatus } from '@/types/dto/schedule';
import { formatDate } from '@/utils/date';
import { getScheduleDetailPage, PATH } from '@/constants';
import { ButtonShape, ButtonSize } from '@/components/common/Button/Button.component';
import { usePagination } from '@/hooks';
import { $generationNumber } from '@/store';
import { usePagination, useToast } from '@/hooks';
import { $generationNumber, $isMaster, $profile } from '@/store';
import { $schedules } from '@/store/schedule';
import { ValueOf } from '@/types';
import { getScheduleStatusText } from '@/utils';
import { getScheduleStatusText, SchedulePlatformType } from '@/utils';
import { ToastType } from '@/styles';

const ScheduleList = () => {
const [searchParams, setSearchParams] = useSearchParams();
const teamName = searchParams.get('team');
const generationNumber = useRecoilValue($generationNumber);
const [position] = useRecoilValue($profile);
const isMaster = useRecoilValue($isMaster);
const page = searchParams.get('page') || '1';
const size = searchParams.get('size') || '10';
const searchWord = searchParams.get('searchWord') || '';

const { pathname, search } = useLocation();
const { handleAddToast } = useToast();

const handleClickLink = (event: MouseEvent<HTMLAnchorElement>) => {
if (!isMaster && teamName !== position) {
handleAddToast({
type: ToastType.error,
message: '접근 권한이 없는 플랫폼입니다.',
});
event.preventDefault();
}
};

const columns: TableColumn<ScheduleResponse>[] = [
{
Expand All @@ -31,7 +53,11 @@ const ScheduleList = () => {
widthRatio: '20%',
idAccessor: 'scheduleId',
renderCustomCell: ({ cellValue, id }) => (
<Styled.TitleLink to={getScheduleDetailPage(id)} state={{ from: `${pathname}${search}` }}>
<Styled.TitleLink
to={getScheduleDetailPage(id)}
state={{ from: `${pathname}${search}` }}
onClick={handleClickLink}
>
{cellValue as string}
</Styled.TitleLink>
),
Expand Down Expand Up @@ -75,8 +101,9 @@ const ScheduleList = () => {
size: parseInt(size, 10),
searchWord,
generationNumber,
scheduleType: (teamName as ValueOf<typeof SchedulePlatformType>) ?? 'ALL',
}),
[generationNumber, page, searchWord, size],
[generationNumber, page, searchWord, size, teamName],
);

const [{ contents }] = useRecoilStateLoadable($schedules(scheduleParams));
Expand Down Expand Up @@ -105,6 +132,7 @@ const ScheduleList = () => {
<Styled.PageWrapper>
<Styled.Heading>스케줄 정보 </Styled.Heading>
<Styled.StickyContainer>
<TeamNavigationTabs allAltText="All Seminar" />
<SearchOptionBar placeholder="스케줄명 검색" />
</Styled.StickyContainer>
<Table
Expand Down
Loading

0 comments on commit 95e83bc

Please sign in to comment.