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
Binary file added frontend/public/contract.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 20 additions & 11 deletions frontend/src/_mocks/data-form-library.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,29 @@ type Template = {
usageCount: number
isNew: boolean
isVip: boolean
thumbnail?: string
}

export const mockTemplates: Template[] = [
{
id: '1',
title: 'Biểu mẫu hợp đồng',
description: 'Tìm và chọn mẫu hợp đồng pháp lý để bắt đầu soạn thảo.',
title: 'Hợp đồng thỏa thuận',
description: 'Hợp đồng thoả thuận giá trị được hiểu là thống nhất ý chí trên cơ sở tự nguyện về việc xác nhận .',
category: 'Hợp đồng',
usageCount: 1200,
isNew: true,
isVip: true
isVip: true,
thumbnail: '/contract.png'
},
{
id: '2',
title: 'Biểu mẫu hợp đồng',
title: 'Hợp đồng thỏa thuận',
description: 'Tìm và chọn mẫu hợp đồng pháp lý để bắt đầu soạn thảo.',
category: 'Hợp đồng',
usageCount: 1200,
isNew: false,
isVip: false
isVip: false,
thumbnail: '/contract.png'
},
{
id: '3',
Expand All @@ -34,7 +37,8 @@ export const mockTemplates: Template[] = [
category: 'Hợp đồng',
usageCount: 1200,
isNew: true,
isVip: true
isVip: true,
thumbnail: '/contract.png'
},
{
id: '4',
Expand All @@ -43,7 +47,8 @@ export const mockTemplates: Template[] = [
category: 'Hợp đồng',
usageCount: 1200,
isNew: false,
isVip: true
isVip: true,
thumbnail: '/contract.png'
},
{
id: '5',
Expand All @@ -52,7 +57,8 @@ export const mockTemplates: Template[] = [
category: 'Hợp đồng',
usageCount: 950,
isNew: true,
isVip: false
isVip: false,
thumbnail: '/contract.png'
},
{
id: '6',
Expand All @@ -61,7 +67,8 @@ export const mockTemplates: Template[] = [
category: 'Hợp đồng',
usageCount: 1100,
isNew: false,
isVip: false
isVip: false,
thumbnail: '/contract.png'
},
{
id: '7',
Expand All @@ -70,7 +77,8 @@ export const mockTemplates: Template[] = [
category: 'Hợp đồng',
usageCount: 850,
isNew: false,
isVip: true
isVip: true,
thumbnail: '/contract.png'
},
{
id: '8',
Expand All @@ -79,6 +87,7 @@ export const mockTemplates: Template[] = [
category: 'Hợp đồng',
usageCount: 1350,
isNew: true,
isVip: true
isVip: true,
thumbnail: '/contract.png'
}
]
89 changes: 79 additions & 10 deletions frontend/src/components/ui/FormCard.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
import { motion } from 'framer-motion'
import { FileText } from 'lucide-react'

import { Badge, Button, Card, CardContent, CardFooter } from '@/components/ui'
import {
Badge,
Button,
Card,
CardContent,
CardFooter,
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
DialogClose
} from '@/components/ui'
import { cn } from '@/core/lib/utils'
import { type Template, type ViewMode } from '@/models/types/form-library'

Expand All @@ -25,7 +37,7 @@ export default function FormCard({ template, viewMode, index }: FormCardProps) {
}

const cardClasses = cn(
'h-full border border-border-primary bg-background-primary transition-all duration-300 hover:shadow-lg hover:scale-[1.02]',
'h-full border border-border-primary bg-background-primary shadow-200 transition-all duration-300 hover:shadow-300 hover:scale-105',
viewMode === 'list' && 'flex flex-col gap-4'
)

Expand All @@ -50,27 +62,84 @@ export default function FormCard({ template, viewMode, index }: FormCardProps) {
</div>

<div className='space-y-3'>
<h3 className='text-lg font-semibold text-text-main line-clamp-2'>{template.title}</h3>
<p className='text-sm text-text-secondary line-clamp-2'>{template.description}</p>
<h3 className='text-h5 font-semibold text-text-main line-clamp-2'>{template.title}</h3>
<p className='text-p text-text-secondary line-clamp-2'>{template.description}</p>
</div>

<div className='flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between'>
<span className='inline-flex items-center rounded-full bg-background-secondary px-3 py-1 text-xs font-medium text-text-secondary'>
<span className='inline-flex items-center rounded-full bg-background-secondary px-3 py-1 text-small font-medium text-text-secondary'>
{template.category}
</span>

<div className='inline-flex items-center gap-2 text-xs text-text-secondary'>
<div className='inline-flex items-center gap-2 text-small text-text-secondary'>
<FileText size={14} />
<span>{template.usageCount.toLocaleString('vi-VN')} người dùng</span>
</div>
</div>
</div>
</CardContent>

<CardFooter className='flex flex-col gap-2 p-6 pt-0 sm:flex-row'>
<Button variant='outline' size='sm' className='w-full sm:w-auto'>
Xem trước
</Button>
<CardFooter className='flex flex-col gap-3 p-6 pt-0 sm:flex-row sm:items-center sm:justify-between'>
<Dialog>
<DialogTrigger asChild>
<Button variant='outline' size='sm' className='w-full sm:w-auto'>
Xem trước
</Button>
</DialogTrigger>
<DialogContent className='max-w-5xl bg-background-primary p-0 overflow-hidden rounded-3xl shadow-300'>
<div className='grid gap-6 md:grid-cols-2'>
<div className='min-h-96 rounded-3xl border border-border-secondary bg-background-secondary overflow-hidden shadow-200'>
{template.thumbnail ? (
<img src={template.thumbnail} alt={template.title} className='h-full w-full object-cover' />
) : (
<div className='flex h-full items-center justify-center bg-background-secondary text-small text-text-description'>
Ảnh xem trước biểu mẫu
</div>
)}
</div>

<div className='space-y-6 p-6'>
<DialogHeader>
<DialogTitle className='text-h3 font-semibold text-text-main'>{template.title}</DialogTitle>
</DialogHeader>

<div className='space-y-5 rounded-3xl border border-border-secondary bg-background-tertiary p-5'>
<div className='space-y-3'>
<div className='flex items-center justify-between'>
<span className='text-p font-semibold text-text-main'>Mô tả</span>
</div>
<p className='text-p text-text-secondary leading-7'>{template.description}</p>
</div>

<div className='space-y-3'>
<div className='flex items-center justify-between rounded-xl border border-border-secondary bg-background-primary p-4'>
<span className='text-p text-text-description'>Phân loại</span>
<span className='text-p font-semibold text-text-main'>{template.category}</span>
</div>
<div className='flex items-center justify-between rounded-xl border border-border-secondary bg-background-primary p-4'>
<span className='text-p text-text-description'>Số lượt sử dụng</span>
<span className='text-p font-semibold text-text-main'>
{template.usageCount.toLocaleString('vi-VN')}
</span>
</div>
</div>
</div>

<div className='grid gap-3 sm:grid-cols-2'>
<DialogClose asChild>
<Button variant='outline' className='w-full'>
Đóng
</Button>
</DialogClose>
<Button variant='default' className='w-full'>
Sử dụng biểu mẫu
</Button>
</div>
</div>
</div>
</DialogContent>
</Dialog>

<Button variant='default' size='sm' className='w-full sm:w-auto'>
Sử dụng biểu mẫu
</Button>
Expand Down
20 changes: 6 additions & 14 deletions frontend/src/pages/users/template/Template.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ export default function Template() {
{/* Header */}
<motion.div variants={headerVariants} initial='hidden' animate='visible' className='space-y-6'>
<div>
<h1 className='text-4xl font-bold text-slate-900 dark:text-white'>Thư viện biểu mẫu</h1>
<p className='mt-2 text-slate-600 dark:text-slate-400'>
<h1 className='text-h1 font-semibold text-text-main'>Thư viện biểu mẫu</h1>
<p className='mt-2 text-p text-text-secondary'>
Khám phá hàng trăm biểu mẫu pháp lý được tạo bởi các chuyên gia
</p>
</div>
Expand All @@ -45,19 +45,12 @@ export default function Template() {
<div className='flex flex-col sm:flex-row sm:items-center gap-4'>
{/* Search Bar */}
<div className='relative flex-1'>
<Search
className='absolute left-3 top-1/2 transform -translate-y-1/2 text-slate-400 dark:text-slate-500'
size={20}
/>
<Search className='absolute left-3 top-1/2 transform -translate-y-1/2 text-text-tertiary' size={20} />
<Input
placeholder='Tìm kiếm biểu mẫu, luật pháp hoặc từ khóa...'
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className={cn(
'pl-10 w-full',
'border-slate-200 dark:border-slate-700',
'placeholder:text-slate-400 dark:placeholder:text-slate-500'
)}
className={cn('pl-10 w-full', 'border-border-primary', 'placeholder:text-text-tertiary')}
/>
</div>

Expand All @@ -66,9 +59,8 @@ export default function Template() {
</div>

{/* Results count */}
<div className='text-sm text-slate-600 dark:text-slate-400'>
Tìm thấy <span className='font-semibold text-slate-900 dark:text-white'>{filteredTemplates.length}</span> biểu
mẫu
<div className='text-small text-text-secondary'>
Tìm thấy <span className='font-semibold text-text-main'>{filteredTemplates.length}</span> biểu mẫu
</div>
</motion.div>

Expand Down
Loading