Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions frontend/components/service/Program/DifficultyBadge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import styled from 'styled-components'

const DifficultyBadge = styled.span<{ level: string }>`
display: inline-block;
vertical-align: top;
padding: 0.3em 0.5em;
font-size: 0.7rem;
border-radius: 4px;
line-height: 1;
${({ level }) => {
if (level === '초급') {
return `background-color: #139d2b;`
} else if (level === '중급') {
return `background-color: #ff7f00;`
} else if (level === '고급') {
return `background-color: #cf3535;`
}
return `display: none;`
}}
`

export default DifficultyBadge
1 change: 1 addition & 0 deletions frontend/components/service/Program/Speaker.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import React from 'react'
import { ISpeaker } from '../../../interfaces/IProgram'
import styled from 'styled-components'
import { media } from '../../../assets/styles/mixin'
Expand Down
124 changes: 124 additions & 0 deletions frontend/components/service/Program/TalkTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import React from 'react'
import { ITalkItem, ITalkTableList } from '../../../interfaces/IProgram'
import styled from 'styled-components'
import { format } from 'date-fns'
import Link from 'next/link'
import DifficultyBadge from './DifficultyBadge'
import Resources from '../../../data/constants/resources'

const Table = styled.table`
width: 100%;
border-collapse: collapse;
table-layout: fixed;
`
const LeftColumn = styled.div`
width: 90px;
`

const TableHeader = styled.thead`
border-top: 2px solid ${(props) => props.theme.colors.white};
border-bottom: 2px solid ${(props) => props.theme.colors.white};
`
const TableRow = styled.tr`
& + & {
border-top: 1px solid ${(props) => props.theme.colors.white};
}
`
const TableCell = styled.div`
padding: 1rem;
text-align: ${(props) => props.align ?? 'center'};
`
const BadgeWrap = styled.div`
margin-top: 0.5rem;
`
const Title = styled.div`
margin: 0.4rem 0;
`
const Speaker = styled.div`
color: ${(props) => props.theme.colors.violet0};
`
const BoldText = styled.div`
font-weight: bold;
`

const TalkTableItem = (props: { item: ITalkItem }) => {
const { item } = props
const isKeynote = item.category === Resources.KEYNOTE_NAME

return (
<Link href={`/program/talks/${item.id}`}>
<a>
{isKeynote && <BoldText>[키노트]</BoldText>}
<Title>{item.title}</Title>
<Speaker>{item.user_name}</Speaker>
</a>
</Link>
)
}

const TalkTable = (props: {
day: string
headers: string[]
list: ITalkTableList[]
}) => {
const { list } = props

const sortByTrack = (list: ITalkItem[]) => {
return list.sort((a, b) => a.track_num - b.track_num)
}

const getTime = (timeString: string): string => {
return format(new Date(timeString), 'HH:mm')
}

return (
<div>
<Table>
<TableHeader>
<tr>
<th>
<LeftColumn>
시간
<br />
(KST)
</LeftColumn>
</th>
{props.headers.map((header) => (
<th key={header}>{header}</th>
))}
</tr>
</TableHeader>
<tbody>
{list.map((item, index) => (
<TableRow key={`time-${index}`}>
<td>
<TableCell align={'left'}>
{getTime(item.video_open_at)}
</TableCell>
</td>
{item.talkList.length > 1 ? (
sortByTrack(item.talkList).map((talkItem) => (
<td key={`talk-${talkItem.id}`}>
<TableCell>
<TalkTableItem item={talkItem} />
</TableCell>
</td>
))
) : (
<td colSpan={2}>
<TableCell>
<TalkTableItem
item={item.talkList[0]}
/>
</TableCell>
</td>
)}
</TableRow>
))}
</tbody>
</Table>
</div>
)
}

export default TalkTable
53 changes: 53 additions & 0 deletions frontend/components/service/Program/TalkTableToggleButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React, { useState } from 'react'
import styled from 'styled-components'

const ButtonGroup = styled.div`
display: flex;
width: 100%;
align-items: center;
justify-content: center;
border-bottom: 1px solid ${(props) => props.theme.colors.white};
`
const Button = styled.button<{ selected: boolean }>`
border-radius: 4px;
font-size: 1rem;
padding: 1rem 2rem;
background: inherit;
cursor: pointer;
border: 0;
cursor: pointer;
color: ${(props) => props.theme.colors.white};
text-decoration: ${(props) => (props.selected ? 'underline' : 'none')};
`

interface ToggleProps {
handleClick: (day: string) => void
}

const TalkTableToggleButton: React.FC<ToggleProps> = ({ handleClick }) => {
const [checked, setChecked] = useState<string>('day1')

const handleToggle = (day: string): void => {
setChecked(day)
handleClick(day)
}

return (
<ButtonGroup>
<Button
selected={checked === 'day1'}
onClick={() => handleToggle('day1')}
>
10/1 (토)
</Button>
<Button
selected={checked === 'day2'}
onClick={() => handleToggle('day2')}
>
10/2 (일)
</Button>
</ButtonGroup>
)
}

export default TalkTableToggleButton
5 changes: 5 additions & 0 deletions frontend/interfaces/IProgram.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { IApiTalkItem } from './api/IApiPrograms'

export interface ITalkTableList {
[key: string]: any
talkList: ITalkItem[]
}

export interface ITalkItem extends IApiTalkItem {}

export interface ICategoryListItem {
Expand Down
2 changes: 1 addition & 1 deletion frontend/locales/en/sponsorLevel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { SponsorLevel } from '../../data/enums/SponsorLevel'

export default {
[SponsorLevel.LEVEL_1]: 'Keystone',
[SponsorLevel.LEVEL_2]: 'Partner A',
[SponsorLevel.LEVEL_2]: 'Partner',
[SponsorLevel.LEVEL_3]: 'Partner B',
[SponsorLevel.LEVEL_4]: 'Startup',
[SponsorLevel.LEVEL_5]: 'Community'
Expand Down
2 changes: 1 addition & 1 deletion frontend/locales/ko/sponsorLevel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { SponsorLevel } from '../../data/enums/SponsorLevel'

export default {
[SponsorLevel.LEVEL_1]: '키스톤',
[SponsorLevel.LEVEL_2]: '파트너A',
[SponsorLevel.LEVEL_2]: '파트너',
[SponsorLevel.LEVEL_3]: '파트너B',
[SponsorLevel.LEVEL_4]: '스타트업',
[SponsorLevel.LEVEL_5]: '커뮤니티'
Expand Down
1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"@sls-next/serverless-component": "^3.7.0",
"axios": "^0.27.2",
"babel-plugin-styled-components": "^2.0.6",
"date-fns": "^2.29.3",
"env-cmd": "^10.1.0",
"gray-matter": "^4.0.3",
"i18next": "^21.6.14",
Expand Down
91 changes: 83 additions & 8 deletions frontend/pages/program/talk-schedule.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,100 @@
import React from 'react'
import React, { useState } from 'react'
import type { NextPage, GetServerSideProps } from 'next'
import { useTranslation } from 'react-i18next'
import { PageName } from '../../data/enums/PageName'
import PageTitle from '../../components/core/PageTitle'
import { PageProps } from '../../interfaces/PageProps'
import { getTalkList } from '../api/program'
import { GetServerSidePropsContext } from 'next'
import { ITalkItem, ITalkList, ITalkTableList } from '../../interfaces/IProgram'
import { compareAsc, isSameDay } from 'date-fns'
import TalkTableToggleButton from '../../components/service/Program/TalkTableToggleButton'
import TalkTable from '../../components/service/Program/TalkTable'

const TalkSchedule: NextPage = (props: PageProps) => {
interface TalkTableProps extends PageProps {
data: ITalkList
}

const TalkSchedule: NextPage = (props: TalkTableProps) => {
const { t } = useTranslation()
const { pageName, data } = props
const [selectedDay, setSelectedDay] = useState<string>('day1')

const updateSelectedDay = (day: string) => {
setSelectedDay(day)
}

const groupByProperty = (
array: ITalkItem[],
property: string
): ITalkTableList[] => {
const groupByValue: { [key: string]: ITalkItem[] } = array.reduce(
(obj, item) => {
obj[item[property]] = obj[item[property]] || []
obj[item[property]].push(item)
return obj
},
{}
)

return Object.keys(groupByValue).map((key: string) => ({
[property]: key,
talkList: groupByValue[key]
}))
}

const tableData: ITalkItem[] = data.list.sort((a, b) =>
compareAsc(new Date(a.video_open_at), new Date(b.video_open_at))
)

const day1tableList: ITalkItem[] = tableData.filter((item) =>
isSameDay(new Date(item.video_open_at), new Date(2022, 9, 1))
)
const day2tableList: ITalkItem[] = tableData.filter((item) =>
isSameDay(new Date(item.video_open_at), new Date(2022, 9, 2))
)

return (
<div>
<PageTitle title={props.pageName} />
{t('label:preparing')}
<PageTitle title={pageName} />
<TalkTableToggleButton handleClick={updateSelectedDay} />
{selectedDay === 'day1' ? (
<TalkTable
day="day1"
headers={['트랙1', '트랙2']}
list={groupByProperty(day1tableList, 'video_open_at')}
/>
) : (
<TalkTable
day="day2"
headers={['트랙3', '트랙4']}
list={groupByProperty(day2tableList, 'video_open_at')}
/>
)}
</div>
)
}

export const getServerSideProps: GetServerSideProps = async () => {
return {
props: {
title: PageName.TalkSchedule
export const getServerSideProps: GetServerSideProps = async (
context: GetServerSidePropsContext
) => {
const { locale } = context
try {
const data: ITalkList = await getTalkList()

return {
props: {
title: PageName.TalkSchedule,
locale,
data
}
}
} catch (error) {
// TODO: Add error interface
if (error.notFound) {
return {
notFound: true
}
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion pyconweb2022/sponsor/viewsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ def get_queryset(self):
return Sponsor.objects.all()

def list(self, request, *args, **kwargs):
queryset = Sponsor.objects.filter(accepted=True) # 모든 절차가 완료된 후원사만 리스팅
queryset = Sponsor.objects.filter(accepted=True).order_by(
"name"
) # 모든 절차가 완료된 후원사만 리스팅
serializer = SponsorListSerializer(queryset, many=True)
return Response(serializer.data)

Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3831,6 +3831,11 @@ data-uri-to-buffer@3.0.1:
resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz#594b8973938c5bc2c33046535785341abc4f3636"
integrity sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==

date-fns@^2.29.3:
version "2.29.3"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.3.tgz#27402d2fc67eb442b511b70bbdf98e6411cd68a8"
integrity sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==

dayjs@^1.10.4, dayjs@^1.10.7:
version "1.11.2"
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.2.tgz#fa0f5223ef0d6724b3d8327134890cfe3d72fbe5"
Expand Down