Commit 45d864f3 authored by Phạm Quang Bảo's avatar Phạm Quang Bảo

update/final page

parent 3ce24867
This diff is collapsed.
"use client";
import React, { useState } from "react";
import { ArrowRight, ArrowLeft } from "lucide-react";
export default function EventCalendar() {
const mockCalendar = {
month: 10,
year: 2025,
highlighted: [6, 9, 12],
};
const [month, setMonth] = useState<number>(mockCalendar.month);
const [year, setYear] = useState<number>(mockCalendar.year);
return (
<div className="bg-white border rounded-md p-4">
<div className="flex items-center justify-between mb-3">
<div className="text-sm font-medium">
THÁNG {month}/{year}
</div>
<div className="flex items-center gap-2">
<div className="group">
<button
aria-label="Tháng trước"
onClick={() => {
// prev month
if (month === 1) {
setMonth(12);
setYear((y) => y - 1);
} else {
setMonth((m) => m - 1);
}
}}
className="group-hover:border-primary p-1 h-10 w-10 flex items-center justify-center rounded-full border-2 border-[#363636] "
>
<ArrowLeft
size={24}
className="group-hover:text-muted-foreground text-[#363636]"
/>
</button>
</div>
<div className="group">
<button
aria-label="Tháng sau"
onClick={() => {
// next month
if (month === 12) {
setMonth(1);
setYear((y) => y + 1);
} else {
setMonth((m) => m + 1);
}
}}
className="p-1 group-hover:border-primary h-10 w-10 flex items-center justify-center rounded-full border-2 border-[#363636]"
>
<ArrowRight
size={24}
className="group-hover:text-muted-foreground"
/>
</button>
</div>
</div>
</div>
<div className="grid grid-cols-7 gap-1 text-center text-xs">
{["CN", "T2", "T3", "T4", "T5", "T6", "T7"].map((d) => (
<div key={d} className="text-gray-400 py-1">
{d}
</div>
))}
{
(() => {
const totalDays = new Date(year, month, 0).getDate()
const firstDayIndex = new Date(year, month - 1, 1).getDay() // 0 (Sun) - 6 (Sat)
// previous month total days
const prevMonthTotalDays = new Date(year, month - 1, 0).getDate()
const totalCells = firstDayIndex + totalDays
const trailingCount = (7 - (totalCells % 7)) % 7
return (
<>
{Array.from({ length: firstDayIndex }).map((_, i) => {
const dayNum = prevMonthTotalDays - (firstDayIndex - 1) + i
return (
<div key={`prev-${i}`} className="py-2 text-sm text-gray-300">
{dayNum}
</div>
)
})}
{Array.from({ length: totalDays }, (_, i) => i + 1).map((day) => {
const isHighlighted = mockCalendar.highlighted.includes(day)
return (
<div
key={day}
className={`py-2 rounded-full w-10 h-10 flex flex-col justify-center items-center text-sm ${isHighlighted ? 'bg-yellow-500 text-white' : 'text-gray-700'
}`}
>
{day}
</div>
)
})}
{Array.from({ length: trailingCount }).map((_, i) => (
<div key={`next-${i}`} className="py-2 text-sm text-gray-300">
{i + 1}
</div>
))}
</>
)
})()
}
</div>
</div>
);
}
'use client'
import { useState } from 'react'
import { Swiper, SwiperSlide } from 'swiper/react'
import 'swiper/css'
export default function ImageGallery({ images }: { images: string[] }) {
const [activeIndex, setActiveIndex] = useState(0)
const [lightboxOpen, setLightboxOpen] = useState(false)
return (
<div className="w-full max-w-4xl mx-auto">
{/* Ảnh lớn */}
<div
className="w-full mb-4 overflow-hidden rounded-lg shadow-md cursor-zoom-in"
onClick={() => setLightboxOpen(true)}
>
<img
src={images[activeIndex]}
alt={`Image ${activeIndex + 1}`}
className="w-full h-full object-cover transition-transform duration-300"
/>
</div>
{/* Slider ảnh nhỏ */}
<Swiper spaceBetween={10} slidesPerView={4} className="cursor-pointer">
{images.map((img, index) => (
<SwiperSlide key={index} onClick={() => setActiveIndex(index)}>
<img
src={img}
alt={`Thumbnail ${index + 1}`}
className={`w-full object-cover rounded-lg border-2 transition-all duration-300
${activeIndex === index
? 'border-blue-500 filter brightness-100'
: 'border-transparent filter brightness-50 hover:brightness-75'
}`}
/>
</SwiperSlide>
))}
</Swiper>
{/* Lightbox */}
{lightboxOpen && (
<div
className="fixed inset-0 bg-black bg-opacity-80 flex items-center justify-center z-50 cursor-zoom-out"
onClick={() => setLightboxOpen(false)}
>
<img
src={images[activeIndex]}
alt={`Image ${activeIndex + 1}`}
className="max-h-full max-w-full object-contain"
/>
</div>
)}
</div>
)
}
"use client"
import Link from "next/link"
import { usePathname } from "next/navigation"
import { usePathname, useRouter } from "next/navigation"
import React from "react"
type Category = {
title: string
href: string
title: string
href: string
}
const CATEGORIES: Category[] = [
{ title: "Về VCCI-HCM", href: "/gioi-thieu" },
{ title: "Chức năng và Nhiệm vụ", href: "/gioi-thieu/chuc-nang" },
{ title: "Sơ đồ Tổ chức", href: "/gioi-thieu/so-do" },
{ title: "Dịch vụ cung cấp", href: "/gioi-thieu/dich-vu" },
{ title: "Về VCCI-HCM", href: "/gioi-thieu" },
{ title: "Chức năng và nhiệm vụ", href: "/gioi-thieu/chuc-nang-nhiem-vu" },
{ title: "Sơ đồ tổ chức", href: "/gioi-thieu/so-do-to-chuc" },
{ title: "Dịch vụ cung cấp", href: "/gioi-thieu/dich-vu-cung-cap" },
]
const ListCategory: React.FC = () => {
const pathname = usePathname() || ""
const isActive = (href: string) => {
// treat the base path as active for nested routes as well
if (href === "/gioi-thieu") return pathname === href || pathname.startsWith(href + "/")
return pathname === href
}
return (
<div className="border-t border-gray-200 bg-white p-2.5">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<nav aria-label="Danh mục" className="py-3">
<ul className="flex gap-8 items-center">
{CATEGORIES.map((c) => {
const active = isActive(c.href)
return (
<li key={c.href}>
<Link
href={c.href}
className={
"text-sm font-medium py-3.5 px-5 transition-colors duration-150 " +
(active
? "text-yellow-500 font-semibold decoration-yellow-300 "
: "text-gray-600 hover:text-gray-800 hover:underline")
}
>
{c.title}
</Link>
</li>
)
})}
</ul>
</nav>
</div>
</div>
)
const pathname = usePathname() || ""
const router = useRouter()
const isActive = (href: string) => {
if (href === "/gioi-thieu") return pathname === "/gioi-thieu"
return pathname === href
}
const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
router.push(e.target.value)
}
return (
<div className="border-t border-gray-200 bg-white p-2.5">
<div className="max-w-7xl mx-auto">
<nav aria-label="Danh mục" className="py-3">
{/* --- Desktop view --- */}
<ul className="hidden sm:flex items-center">
{CATEGORIES.map((c) => {
const active = isActive(c.href)
return (
<li key={c.href}>
<Link
href={c.href}
className={
"text-sm font-bold py-3.5 px-5 transition-colors duration-150 " +
(active
? "text-yellow-500 font-semibold decoration-yellow-300"
: "text-gray-600 hover:text-yellow-500")
}
>
{c.title}
</Link>
</li>
)
})}
</ul>
{/* --- Mobile view (Dropdown) --- */}
<div className="sm:hidden">
<select
value={pathname}
onChange={handleChange}
className="w-full border border-gray-300 rounded-md px-3 py-2 text-sm text-gray-700 focus:outline-none focus:ring-2 focus:ring-yellow-400"
>
{CATEGORIES.map((c) => (
<option key={c.href} value={c.href}>
{c.title}
</option>
))}
</select>
</div>
</nav>
</div>
</div>
)
}
export default ListCategory
\ No newline at end of file
export default ListCategory
"use client"
import React, { useState } from 'react'
import { Checkbox } from '@/components/ui/checkbox'
import { Input } from '@/components/ui/input'
import { Button } from '@/components/ui/button'
type Category = { id: string; title: string; count: number }
const DEFAULT_CATEGORIES: Category[] = [
{ id: 'ceo', title: 'CEO', count: 4 },
{ id: 'policy', title: 'Hỏi đáp về chính sách', count: 0 },
{ id: 'biz', title: 'Tin Doanh Nghiệp', count: 9 },
{ id: 'member', title: 'Tin Hội Viên', count: 17 },
{ id: 'law', title: 'Văn bản Pháp luật sắp có hiệu lực', count: 30 }
]
export const ListFilter: React.FC<{
categories?: Category[]
onSearch?: (q: string) => void
onReset?: () => void
}> = ({ categories = DEFAULT_CATEGORIES, onSearch, onReset }) => {
const [query, setQuery] = useState('')
const [selected, setSelected] = useState<Record<string, boolean>>(() => {
const map: Record<string, boolean> = {}
categories.forEach((c) => (map[c.id] = false))
return map
})
const toggle = (id: string) => setSelected((s) => ({ ...s, [id]: !s[id] }))
return (
<aside className="p-6 bg-white border rounded-md">
<h3 className="text-lg font-semibold mb-3">Tìm kiếm</h3>
<div className="mb-4">
<Input
placeholder="Tên văn bản ..."
value={query}
className='text-black placeholder:text-gray-400 rounded-none py-2.5 px-2'
onChange={(e) => setQuery(e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
onSearch?.(query)
}
}}
/>
</div>
{/* <div className="flex flex-col gap-3 mb-6">
{categories.map((c) => (
<label key={c.id} className="flex items-center gap-3">
<Checkbox checked={!!selected[c.id]} onCheckedChange={() => toggle(c.id)} />
<div className="flex justify-between w-full items-center">
<span className="text-sm">{c.title}</span>
<span className="text-sm text-gray-400">({c.count})</span>
</div>
</label>
))}
</div> */}
<div className="flex gap-3">
<Button className="flex-1 rounded-none font-medium text-lg text-white hover:bg-muted-foreground hover:outline-1 outline-primary hover:text-primary" onClick={() => onSearch?.(query)}>
Tìm kiếm
</Button>
<Button
className="flex-1 rounded-none font-medium text-lg text-white hover:bg-muted-foreground hover:outline-1 outline-primary hover:text-primary"
onClick={() => {
setQuery('')
// restore initial map
const map: Record<string, boolean> = {}
categories.forEach((c) => (map[c.id] = false))
setSelected(map)
onReset?.()
}}
>
Bỏ tìm
</Button>
</div>
</aside>
)
}
export default ListFilter
'use client'
import React from "react";
import ListCategory from "../components/list-category";
import EventCalendar from "../components/event-calendar";
const Page = () => {
return (
<div className="min-h-screen container mx-auto pb-4">
<div className="w-full flex flex-col gap-5">
<ListCategory />
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* Main content */}
<main className="lg:col-span-2 bg-white border rounded-md p-7">
<h1 className="text-2xl font-bold text-[#153e8e]">Dịch vụ cung cấp</h1>
<hr className="my-5" />
<div className="flex items-center">
<img src="/gioi-thieu/dich-vu-cung-cap/1-7.webp" alt="Thông tin" className="w-12 px-2 py-2" />
<p>Tổ chức sự kiện, hội nghị, hội thảo, giao lưu thương mại, hội chợ, triển lãm</p>
</div>
<div className="flex items-center">
<img src="/gioi-thieu/dich-vu-cung-cap/3-4-150x145.webp" alt="Thông tin" className="w-12 px-2 py-2" />
<p>Đào tạo nâng cao năng lực quản trị doanh nghiệp</p>
</div>
<div className="flex items-center">
<img src="/gioi-thieu/dich-vu-cung-cap/5-1.webp" alt="Thông tin" className="w-12 px-2 py-2" />
<p>Khảo sát thị trường nước ngoài</p>
</div>
<div className="flex items-center">
<img src="/gioi-thieu/dich-vu-cung-cap/7-150x147.webp" alt="Thông tin" className="w-12 px-2 py-2" />
<p>Cho thuê văn phòng, hội trường</p>
</div>
<div className="flex items-center">
<img src="/gioi-thieu/dich-vu-cung-cap/8.webp" alt="Thông tin" className="w-12 px-2 py-2" />
<p>Quảng cáo, truyền thông</p>
</div>
<div className="flex items-center">
<img src="/gioi-thieu/dich-vu-cung-cap/2-6.webp" alt="Thông tin" className="w-12 px-2 py-2" />
<p>Tư vấn về pháp lý, quan hệ lao động, môi trường kinh doanh</p>
</div>
<div className="flex items-center">
<img src="/gioi-thieu/dich-vu-cung-cap/4-1.webp" alt="Thông tin" className="w-12 px-2 py-2" />
<p>Cấp C/O và xác nhận các chứng từ thương mại</p>
</div>
<div className="flex items-center">
<img src="/gioi-thieu/dich-vu-cung-cap/6-5.webp" alt="Thông tin" className="w-12 px-2 py-2" />
<p>Cung cấp thông tin thị trường và hồ sơ doanh nghiệp</p>
</div>
<div className="flex items-center">
<img src="/gioi-thieu/dich-vu-cung-cap/9.webp" alt="Thông tin" className="w-12 px-2 py-2" />
<p>Thu xếp visa nhập cảnh</p>
</div>
<div className="flex items-center">
<img src="/gioi-thieu/dich-vu-cung-cap/10.webp" alt="Thông tin" className="w-12 px-2 py-2" />
<p>Biên phiên dịch</p>
</div>
</main>
{/* Sidebar */}
<aside className="space-y-6">
<EventCalendar />
<img src="/home/eCarAid_web_banner_600x400.webp" alt="banner" />
</aside>
</div >
</div >
</div >
);
};
export default Page;
\ No newline at end of file
'use client'
import React from "react";
import ListCategory from "./components/list-category";
import EventCalendar from "./components/event-calendar";
import ImageGallery from "./components/image-gallery";
const Page = () => {
const images = [
'/gioi-thieu/VCCI-HCM-BROCHURE-2020_Tieng-Viet-1-scaled.webp',
'/gioi-thieu/VCCI-HCM-BROCHURE-2020_Tieng-Viet-2-scaled.webp',
'/gioi-thieu/VCCI-HCM-BROCHURE-2020_Tieng-Viet-3-scaled.webp',
'/gioi-thieu/VCCI-HCM-BROCHURE-2020_Tieng-Viet-4-scaled.webp',
]
return (
<div className="min-h-screen container mx-auto pb-4">
<div className="w-full flex flex-col gap-5">
<ListCategory />
{/* Main content */}
<main className="lg:col-span-2 bg-white border rounded-md py-10 px-5 md:px-10 xl:px-50 text-justify">
<h1 className="text-2xl font-bold text-[#153e8e]">Về VCCI-HCM</h1>
<hr className="my-5" />
<div className="flex flex-col justify-center items-center">
<p className="text-center text-[#063e8e] text-[14pt] font-bold pb-5">
GIỚI THIỆU CHUNG
</p>
<p className="pb-5">Liên đoàn Thương mại và Công nghiệp Việt Nam (VCCI) là tổ chức quốc gia tập hợp và đại diện cho cộng đồng doanh nghiệp, doanh nhân, người sử dụng lao động và các hiệp hội doanh nghiệp ở Việt Nam nhằm mục đích phát triển, bảo vệ và hỗ trợ cộng đồng doanh nghiệp, góp phần phát triển kinh tế - xã hội của đất nước, thúc đẩy các quan hệ hợp tác kinh tế, thương mại và khoa học - công nghệ với nước ngoài trên cơ sở bình đẳng và cùng có lợi, theo quy định của pháp luật.</p>
<p>Chi nhánh VCCI khu vực Thành phố Hồ Chí Minh (VCCI-HCM) là Chi nhánh lớn nhất, hoạt động trên địa bàn TP.HCM và 5 tỉnh thành phía Nam: Bình Dương, Bình Phước, Đồng Nai, Lâm Đồng, Tây Ninh.</p>
<img src="/gioi-thieu/MAPS_VCCI-HCM-Upload-1259x1536.jpg.webp" alt="map" />
<img src="/gioi-thieu/tam-nhin-1024x470.jpg.webp" alt="map" />
<p className="text-[14pt] pb-5">
<strong className="text-[#063e8e] font-sans">
BROCHURE VCCI-HCM
</strong>
</p>
<div className="pb-5">
<ImageGallery images={images} />
</div>
<p className="text-[14pt] pb-5">
<strong className="text-[#063e8e] font-sans">
VIDEO VỀ VCCI-HCM
</strong>
</p>
<iframe
width="808"
height="455"
src="https://www.youtube.com/embed/j9ao-9b6Jf0"
title="VCCI-HCM 2024 IN REVIEW"
frameBorder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerPolicy="strict-origin-when-cross-origin"
allowFullScreen>
</iframe>
</div>
</main>
</div>
</div>
);
};
export default Page;
\ No newline at end of file
'use client'
import React from "react";
import ListCategory from "../components/list-category";
const Page = () => {
return (
<div className="min-h-screen container mx-auto pb-4">
<div className="w-full flex flex-col gap-5">
<ListCategory />
{/* Main content */}
<main className="lg:col-span-2 bg-white border rounded-md py-10 px-5 md:px-10 xl:px-50 text-justify">
<h1 className="text-2xl font-bold text-[#153e8e]">Về VCCI-HCM</h1>
<hr className="my-5" />
<img src="/gioi-thieu/so-do-to-chuc/2025-SO-DO-TO-CHUC-01-VN.jpg.webp" alt="Sơ đồ tổ chức VCCI-HCM" />
</main>
</div >
</div >
);
};
export default Page;
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment