Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: boarding pass component with avatar icon #41

Merged
merged 16 commits into from
Jul 3, 2024
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
4 changes: 3 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
"arrow-body-style": "off",
"import/no-extraneous-dependencies": "off",
"no-promise-executor-return": "off",
"import/prefer-default-export": "off"
"import/prefer-default-export": "off",
"@next/next/no-img-element": "off",
"jsx-a11y/alt-text": "off"
}
}
Binary file added public/boarding-pass-bottom.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/boarding-pass-divider.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/food.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/ship.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 6 additions & 2 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,18 @@ export default function RootLayout({
}>) {
return (
<html lang="ko">
<body className={`${pretendard.className} ${pretendard.variable}`}>
<body
className={`${pretendard.className} ${pretendard.variable} flex justify-center items-start bg-neutral-800`}
hee-suh marked this conversation as resolved.
Show resolved Hide resolved
>
<Script
async
strategy="beforeInteractive"
type="text/javascript"
src={`//dapi.kakao.com/v2/maps/sdk.js?appkey=${process.env.NEXT_PUBLIC_KAKAO_JAVASCRIPT_KEY}&autoload=false`}
/>
{children}
<main className="relative w-full max-w-[420px] min-h-dvh">
poiu694 marked this conversation as resolved.
Show resolved Hide resolved
{children}
</main>
</body>
</html>
)
Expand Down
54 changes: 19 additions & 35 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,25 @@
import { Button, Chip, ChipButton, QRCode, Typography } from '@/components'
'use client'

import BoardingInfoPass from '@/components/boarding-pass/boarding-info-pass'

const Home = () => {
return (
<main className="w-full min-h-screen flex flex-col justify-center items-center bg-neutral-600">
<QRCode url="http://localhost:3000" />
<Button colorScheme="orange">HI</Button>
<Typography size="h0" color="yellow-100">
Typography
</Typography>
<Typography size="h1" color="orange-400">
Typography
</Typography>
<Typography size="h2">Typography</Typography>
<Typography size="h3">Typography</Typography>
<Typography size="h4">Typography</Typography>
<Typography size="h5">Typography</Typography>
<Typography size="h5-2">Typography</Typography>
<Typography size="h6">Typography</Typography>
<Typography size="h7">Typography</Typography>
<Typography size="body0">Typography</Typography>
<Typography size="body1">Typography</Typography>
<Typography size="body2">Typography</Typography>
<Typography size="body3">Typography</Typography>
<Typography size="body4">Typography</Typography>
<Chip size="sm" fontSize="h7" colorScheme="orange">
진영 Pick
</Chip>
<Chip size="md" fontSize="body3" colorScheme="neutral-400">
🍝 태그설명
</Chip>
<Chip size="md" fontSize="body3" colorScheme="orange">
🍝 태그설명
</Chip>
<Chip size="lg" fontSize="body0" colorScheme="neutral-500">
도라방스
</Chip>
<ChipButton rightIcon={{ type: 'close' }}>한우갈비</ChipButton>
<main className="w-full min-h-dvh flex flex-col justify-center items-center bg-neutral-700 px-5">
<BoardingInfoPass
owner="주병호"
numOfCrews={1330}
day={19933}
members={[
'주병호',
'손병호',
'김병호',
'이병호',
'상병호',
'고병호',
'양병호',
]}
numOfPins={19339}
/>
</main>
)
}
Expand Down
17 changes: 17 additions & 0 deletions src/components/boarding-pass/boarding-bottom.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import cn from '@/utils/cn'

interface BoardingBottomProps {
className?: string
}

const BoardingBottom = ({ className }: BoardingBottomProps) => {
return (
<img
src="/boarding-pass-bottom.png"
className={cn('w-full max-h-[7px]', className)}
aria-hidden
/>
)
}

export default BoardingBottom
17 changes: 17 additions & 0 deletions src/components/boarding-pass/boarding-divider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import cn from '@/utils/cn'

interface BoardingDividerProps {
className?: string
}

const BoardingDivider = ({ className }: BoardingDividerProps) => {
return (
<img
src="/boarding-pass-divider.png"
className={cn('w-full max-h-[32px]', className)}
aria-hidden
/>
)
}

export default BoardingDivider
90 changes: 90 additions & 0 deletions src/components/boarding-pass/boarding-info-pass.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
'use client'

import cn from '@/utils/cn'

import { Icon, Typography } from '../common'
import BoardingDivider from './boarding-divider'
import BoardingBottom from './boarding-bottom'
import BoardingMembers from './boarding-members'
import { BoardingInfoPassProps } from './types'

const ShareButton = ({ isInvited }: { isInvited: boolean }) => {
return (
<button
type="button"
className="flex justify-center items-center gap-2 rounded-full border border-neutral-500 px-6 py-3"
>
<Icon type="shareNetwork" size="md" />
<Typography size="h5" color="neutral-000">
{isInvited ? '초대장 다시 보내기' : '초대장 보내기'}
</Typography>
</button>
)
}

const ExitButton = () => {
return (
<button
type="button"
className="w-full h-[34px] flex justify-center items-center"
>
<Typography size="h5" color="neutral-500">
지도 나가기
</Typography>
</button>
)
}

const BoardingInfoPass = ({
className,
day,
numOfPins,
numOfCrews,
members,
owner,
}: BoardingInfoPassProps) => {
// TODO: 로직 수정
const isMyBoard = true

return (
<div className={cn('flex flex-col w-full', className)}>
<div className="pt-5 flex flex-col gap-1 justify-content items-center bg-neutral-600 rounded-t-3xl">
<img src="/ship.png" aria-hidden className="w-[31px] h-[35px]" />
<Typography size="h5" color="neutral-300">
{day.toLocaleString()}일째 항해중
</Typography>
</div>

<div className="w-full pt-5 px-5 flex bg-neutral-600">
<div className="flex flex-col gap-1 flex-1">
<Typography size="body4" color="neutral-300" className="text-left">
Crew
</Typography>
<Typography size="h4" color="neutral-000" className="text-left">
{numOfCrews.toLocaleString()}명
</Typography>
</div>
<div className="flex flex-col gap-1 flex-1 bg-neutral-600">
<Typography size="body4" color="neutral-300" className="text-left">
Pins
</Typography>
<Typography size="h4" color="neutral-000" className="text-left">
{numOfPins.toLocaleString()}개
</Typography>
</div>
</div>

<BoardingDivider />

<BoardingMembers members={members} owner={owner} />

<div className="flex justify-center bg-neutral-600 pb-5">
{isMyBoard ? <ShareButton isInvited={false} /> : <ExitButton />}
</div>

<BoardingBottom />
</div>
)
}

export default BoardingInfoPass
42 changes: 42 additions & 0 deletions src/components/boarding-pass/boarding-members.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Avatar, Chip, Typography } from '../common'
import { BoardingMembersProps } from './types'

const memberColors = [
'coral',
'dark-blue',
'sky-blue',
'violet',
'green',
] as const

const BoardingMembers = ({ owner, members }: BoardingMembersProps) => {
return (
<ul className="w-full bg-neutral-600 max-h-[268px] overflow-y-scroll no-scrollbar">
{members.map((member, index) => (
<li key={member} className="flex items-center px-4 h-[52px]">
<Avatar
// TODO: 로직 수정
me={member === owner}
value={member}
colorScheme={memberColors[index % memberColors.length]}
/>
<Typography
as="span"
size="body1"
color="neutral-100"
className="ml-2"
>
{member}
</Typography>
{owner === member && (
<Chip size="sm" colorScheme="neutral-800" className="ml-[6px]">
주인장
</Chip>
)}
</li>
))}
</ul>
)
}

export default BoardingMembers
1 change: 1 addition & 0 deletions src/components/boarding-pass/constant.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const SINGLE = 1
43 changes: 43 additions & 0 deletions src/components/boarding-pass/invite-boarding-header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { SINGLE } from './constant'
import { Typography } from '../common'
import { InviteBoardingPass } from './types'

const InviteBoardingHeader = ({
mapName,
owner,
numOfCrews,
}: InviteBoardingPass) => {
return (
<>
<div className="pt-5 flex flex-col gap-1 justify-content items-center bg-neutral-600 rounded-t-3xl">
<img src="/ship.png" aria-hidden className="w-[31px] h-[35px]" />
<Typography size="h5" color="neutral-300">
Boarding Pass
</Typography>
</div>

<div className="w-full pt-5 px-5 flex bg-neutral-600">
<div className="flex flex-col gap-1 flex-1">
<Typography size="body4" color="neutral-300" className="text-left">
Flight
</Typography>
<Typography size="h4" color="neutral-000" className="text-left">
{mapName}
</Typography>
</div>
<div className="flex flex-col gap-1 flex-1 bg-neutral-600">
<Typography size="body4" color="neutral-300" className="text-left">
Crew
</Typography>
<Typography size="h4" color="neutral-000" className="text-left">
{numOfCrews === SINGLE
? owner
: `${owner} 외 ${(numOfCrews - 1).toLocaleString()}명`}
</Typography>
</div>
</div>
</>
)
}

export default InviteBoardingHeader
71 changes: 71 additions & 0 deletions src/components/boarding-pass/invited-boarding-pass.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
'use client'

import cn from '@/utils/cn'

import { formatDate } from '@/utils/date'
import { Button, Typography } from '../common'
import BoardingDivider from './boarding-divider'
import BoardingBottom from './boarding-bottom'
import InviteBoardingHeader from './invite-boarding-header'
import { InvitedBoardingPassProps } from './types'

const InvitedBoardingPass = ({
className,
mapName,
owner,
numOfCrews,
time,
isExpired,
images,
onClick,
}: InvitedBoardingPassProps) => {
return (
<div className={cn('flex flex-col w-full', className)}>
<InviteBoardingHeader
mapName={mapName}
owner={owner}
numOfCrews={numOfCrews}
/>

<BoardingDivider />

<div className="pt-2 px-5 flex flex-col gap-1 bg-neutral-600">
<Typography size="body4" color="neutral-300" className="text-left">
Boarding Time
</Typography>
{isExpired ? (
<Typography size="h4" color="orange-300" className="text-left">
앗.. 탑승 시간이 지나버렸어요..
</Typography>
) : (
<Typography size="h4" color="neutral-000" className="text-left">
{formatDate(time)}
</Typography>
)}
</div>

{images && !isExpired && (
<div className="pt-[18px] px-[20px] w-full flex gap-[10px] bg-neutral-600 overflow-x-scroll no-scrollbar">
{images.map((image, index) => (
<img
key={image}
src={image}
className="w-[88px] h-[88px] max-w-[88px] rounded"
alt={`음식사진 ${index + 1}`}
/>
))}
</div>
)}

<div className="px-[20px] bg-neutral-600">
<Button disabled={isExpired} className="my-5" onClick={onClick}>
승선하기
</Button>
</div>

<BoardingBottom />
</div>
)
}

export default InvitedBoardingPass
Loading
Loading