Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
'use client'

import { Button } from '@/components/shadcn/button'
import { cn, dateFormatter } from '@/libs/utils'
import CheckCircle from '@/public/icons/check-circle.svg'

export type StateType = 'SUCCESS' | 'FAIL' | 'NONE'

const STATE_MAP = {
SUCCESS: {
container: 'border-primary-light bg-color-blue-95',
icon: 'text-primary',
text: 'text-primary-strong',
description: 'text-primary',
dot: 'bg-primary',
title: '아웃풋 생성 성공'
},
FAIL: {
container: 'border-error bg-color-red-95',
icon: 'text-error',
text: 'text-error',
description: 'text-error',
dot: 'bg-error',
title: '아웃풋 생성 실패'
},
NONE: {
container: 'border-line bg-color-neutral-99',
icon: 'text-color-neutral-50',
text: 'text-color-neutral-30',
description: '',
dot: 'bg-color-neutral-30',
title: '파일 업로드 이후 실행 필요'
}
} as const satisfies Record<
StateType,
{
container: string
icon: string
text: string
description: string
dot: string
title: string
}
>

export interface GeneratedResult {
state: StateType
date?: Date
totalCnt: number
successCnt: number
}

interface ExecutionCardProps {
disabled?: boolean
loading: boolean
onGenerate: () => void
canDownload?: boolean
onDownload?: () => void
genResult: GeneratedResult
}

export function ExecutionCard({
disabled = false,
loading,
onGenerate,
canDownload = false,
onDownload,
genResult
}: ExecutionCardProps) {
return (
<div className="border-color-cool-neutral-90 bg-color-common-100 grid gap-7 rounded-2xl border px-6 py-7">
<div className="flex justify-between">
<div className="grid gap-1">
<h3 className="text-head5_sb_24 text-color-common-0">
자동 생성 실행하기
</h3>
<span className="text-color-cool-neutral-40 text-body2_m_14">
업로드한 파일을 이용해서 생성을 시도합니다
</span>
</div>
<div className="flex gap-2">
<Button
type="button"
onClick={onGenerate}
disabled={disabled}
className="ring-primary-light text-sub4_sb_14 text-primary hover:bg-color-blue-95 rounded-lg bg-white px-3 py-[10px] ring-[1.4px] disabled:ring-0"
>
자동 생성하기
</Button>
{canDownload && (
<Button
type="button"
onClick={onDownload}
disabled={disabled}
className="text-sub4_sb_14 rounded-lg px-3 py-[10px] ring-[1.4px] disabled:ring-0"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

"세부 내용 다운로드" 버튼에 글자 색상(text-primary)과 배경색(bg-white) 스타일이 누락되어 있습니다. 인접한 "자동 생성하기" 버튼과 디자인 일관성을 맞추기 위해 스타일 추가가 필요합니다.

Suggested change
className="text-sub4_sb_14 rounded-lg px-3 py-[10px] ring-[1.4px] disabled:ring-0"
className="ring-primary-light text-sub4_sb_14 text-primary hover:bg-color-blue-95 rounded-lg bg-white px-3 py-[10px] ring-[1.4px] disabled:ring-0"

>
세부 내용 다운로드
</Button>
)}
</div>
</div>
{loading ? (
<StateSkeleton />
) : (
<div
className={cn(
'flex items-start gap-2 rounded-xl border p-4',
STATE_MAP[genResult.state].container
)}
>
<CheckCircle
className={cn('mt-[1px] h-5', STATE_MAP[genResult.state].icon)}
/>
<div className={cn(STATE_MAP[genResult.state].text)}>
<span className="text-sub3_sb_16">
{STATE_MAP[genResult.state].title}
</span>
<div
className={cn(
'text-caption1_m_13 flex',
STATE_MAP[genResult.state].description
)}
>
{genResult.state !== 'NONE' ? (
<>
{genResult.date && (
<span>{dateFormatter(genResult.date, 'YYYY-MM-DD')}</span>
)}
<div className="grid h-5 w-5 place-items-center">
<div
className={cn(
'h-1 w-1 rounded-full',
STATE_MAP[genResult.state].dot
)}
/>
</div>
<span>
{genResult.successCnt}/{genResult.totalCnt} 솔루션 테스트
통과
{genResult.state === 'SUCCESS' ? ' 완료' : ' 실패'}
</span>
</>
) : (
<>
<span>-</span>
<div className="grid h-5 w-5 place-items-center">
<div
className={cn(
'h-1 w-1 rounded-full',
STATE_MAP[genResult.state].dot
)}
/>
</div>
<span>-</span>
</>
)}
</div>
</div>
</div>
)}
</div>
)
}

function StateSkeleton() {
return (
<div className="border-line bg-color-neutral-99 flex animate-pulse items-start gap-2 rounded-xl border p-4">
<div className="bg-color-neutral-90 mt-[2px] h-5 w-5 rounded-full" />
<div className="flex flex-col gap-2">
<div className="bg-color-neutral-90 h-5 w-32 rounded-md" />
<div className="bg-color-neutral-90 h-4 w-48 rounded-md" />
</div>
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
'use client'

import { Button } from '@/components/shadcn/button'

interface TCDownloadCardProps {
onDelete: () => void
onDownload: () => void
disabled?: boolean
}

export function TCDownloadCard({
onDelete,
onDownload,
disabled = false
}: TCDownloadCardProps) {
return (
<div className="border-color-cool-neutral-90 bg-color-common-100 rounded-2xl border px-6 py-7">
<div className="flex w-full items-center justify-between">
<div className="flex flex-col gap-1">
<h3 className="text-head5_sb_24 text-color-common-0">
TC 삭제 및 다운로드
</h3>
<p className="text-color-cool-neutral-40 text-body2_m_14">
생성한 TC 파일을 삭제 및 다운로드 할 수 있어요
</p>
</div>
<div className="flex items-center gap-2">
<Button
onClick={onDelete}
disabled={disabled}
type="button"
className="ring-primary-light text-sub4_sb_14 text-primary hover:bg-color-blue-95 rounded-lg bg-white px-3 py-[10px] ring-[1.4px] disabled:ring-0"
>
TC 삭제하기
</Button>
<Button
onClick={onDownload}
disabled={disabled}
type="button"
className="bg-primary text-color-common-100 text-sub4_sb_14 hover:bg-primary-strong h-11 rounded-lg px-3 py-[10px]"
>
TC 다운로드
</Button>
</div>
</div>
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
'use client'

import { useState } from 'react'
import {
ExecutionCard,
type GeneratedResult,
type StateType
} from '../_components/ExecutionCard'
import { TCDownloadCard } from '../_components/TCDownloadCard'

export default function Page() {
const [genResult, setGenResult] = useState<GeneratedResult>({
state: 'FAIL',
date: new Date(2020, 1, 1),
totalCnt: 2,
successCnt: 2
})

const [loading, setLoading] = useState<boolean>(false)

// 임시 생성하기 버튼 동작 함수: 문제 생성 상태 변경
const onGenerate = () => {
setLoading(true)
setTimeout(() => {
setGenResult((prev) => {
const nextState: StateType = (
{
SUCCESS: 'FAIL',
FAIL: 'NONE',
NONE: 'SUCCESS'
} as const
)[prev.state]

return { ...prev, state: nextState }
})
setLoading(false)
}, 1000)
}

return (
<div className="mt-20 flex w-[900px] flex-col gap-2">
<ExecutionCard
disabled={loading}
loading={loading}
genResult={genResult}
onGenerate={onGenerate}
canDownload
/>
<TCDownloadCard
onDelete={() => alert('Delete')}
onDownload={() => alert('Download')}
disabled={loading}
/>
</div>
)
}
Loading