diff --git a/app/(admin)/admin/agent/page.tsx b/app/(admin)/admin/agent/page.tsx index 382eba0..ea74a1b 100644 --- a/app/(admin)/admin/agent/page.tsx +++ b/app/(admin)/admin/agent/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import ArticleTable from "@/components/table/article-table"; import { Button } from "@/components/ui/button"; import { Plus } from "lucide-react"; @@ -8,10 +8,25 @@ import { BannerDialog } from "@/components/form/banner-dialog"; import Link from "next/link"; import ProductTable from "@/components/table/product-table"; import AgentTable from "@/components/table/agent-table"; +import withReactContent from "sweetalert2-react-content"; +import Swal from "sweetalert2"; +import Cookies from "js-cookie"; +import { useRouter } from "next/navigation"; export default function AgentPage() { const [openDialog, setOpenDialog] = useState(false); + const [userLevelId, setUserLevelId] = useState(null); + + const router = useRouter(); + const MySwal = withReactContent(Swal); + + // 🔹 Ambil userlevelId dari cookies + useEffect(() => { + const ulne = Cookies.get("ulne"); // contoh: "3" + setUserLevelId(ulne ?? null); + }, []); + const handleSubmitBanner = (data: any) => { console.log("Banner Data:", data); }; @@ -26,12 +41,14 @@ export default function AgentPage() {
- - - + {userLevelId !== "3" && ( + + + + )}
diff --git a/app/(admin)/admin/banner/page.tsx b/app/(admin)/admin/banner/page.tsx index caa9b07..f5bfa52 100644 --- a/app/(admin)/admin/banner/page.tsx +++ b/app/(admin)/admin/banner/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import ArticleTable from "@/components/table/article-table"; import { Button } from "@/components/ui/button"; import { Plus } from "lucide-react"; @@ -10,12 +10,22 @@ import router from "next/router"; import { useRouter } from "next/navigation"; import withReactContent from "sweetalert2-react-content"; import Swal from "sweetalert2"; +import Cookies from "js-cookie"; export default function BasicPage() { const [openDialog, setOpenDialog] = useState(false); + const [refreshKey, setRefreshKey] = useState(0); + const [userLevelId, setUserLevelId] = useState(null); + const router = useRouter(); const MySwal = withReactContent(Swal); - const [refreshKey, setRefreshKey] = useState(0); + + // 🔹 Ambil userlevelId dari cookies + useEffect(() => { + const ulne = Cookies.get("ulne"); // contoh: "3" + setUserLevelId(ulne ?? null); + }, []); + const handleSubmitBanner = async (formData: FormData) => { try { const response = await createBanner(formData); @@ -48,13 +58,15 @@ export default function BasicPage() {
- + {userLevelId !== "3" && ( + + )}
diff --git a/app/(admin)/admin/costumer-service/page.tsx b/app/(admin)/admin/costumer-service/page.tsx new file mode 100644 index 0000000..94ae2f8 --- /dev/null +++ b/app/(admin)/admin/costumer-service/page.tsx @@ -0,0 +1,38 @@ +"use client"; + +import { useState } from "react"; +import ArticleTable from "@/components/table/article-table"; +import { Button } from "@/components/ui/button"; +import { Plus } from "lucide-react"; +import { BannerDialog } from "@/components/form/banner-dialog"; +import Link from "next/link"; +import ProductTable from "@/components/table/product-table"; +import ServicesTable from "@/components/table/services-table"; +import CostumerServiceTable from "@/components/table/costumer-service-table"; + +export default function CostumerServicePage() { + const [openDialog, setOpenDialog] = useState(false); + + const handleSubmitBanner = (data: any) => { + console.log("Banner Data:", data); + // TODO: kirim data ke API di sini + }; + + return ( +
+
+
+
+

+ Layanan Konsumen +

+
+ +
+ +
+
+
+
+ ); +} diff --git a/app/(admin)/admin/galery/page.tsx b/app/(admin)/admin/galery/page.tsx index 49f255a..457508a 100644 --- a/app/(admin)/admin/galery/page.tsx +++ b/app/(admin)/admin/galery/page.tsx @@ -1,14 +1,28 @@ "use client"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import Link from "next/link"; import { Button } from "@/components/ui/button"; import { Plus } from "lucide-react"; import Galery from "@/components/table/galery"; import { GaleriDialog } from "@/components/dialog/galery-dialog"; +import { useRouter } from "next/navigation"; +import withReactContent from "sweetalert2-react-content"; +import Swal from "sweetalert2"; +import Cookies from "js-cookie"; export default function GaleryPage() { const [openDialog, setOpenDialog] = useState(false); + const [userLevelId, setUserLevelId] = useState(null); + + const router = useRouter(); + const MySwal = withReactContent(Swal); + + // 🔹 Ambil userlevelId dari cookies + useEffect(() => { + const ulne = Cookies.get("ulne"); // contoh: "3" + setUserLevelId(ulne ?? null); + }, []); const handleSubmitGaleri = () => { console.log("Submit galeri..."); @@ -25,14 +39,15 @@ export default function GaleryPage() {
- - + {userLevelId !== "3" && ( + + )}
diff --git a/app/(admin)/admin/product/page.tsx b/app/(admin)/admin/product/page.tsx index 2db1ecf..b495307 100644 --- a/app/(admin)/admin/product/page.tsx +++ b/app/(admin)/admin/product/page.tsx @@ -1,15 +1,29 @@ "use client"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import ArticleTable from "@/components/table/article-table"; import { Button } from "@/components/ui/button"; import { Plus } from "lucide-react"; import { BannerDialog } from "@/components/form/banner-dialog"; import Link from "next/link"; import ProductTable from "@/components/table/product-table"; +import { useRouter } from "next/navigation"; +import withReactContent from "sweetalert2-react-content"; +import Swal from "sweetalert2"; +import Cookies from "js-cookie"; export default function ProductPage() { const [openDialog, setOpenDialog] = useState(false); + const [userLevelId, setUserLevelId] = useState(null); + + const router = useRouter(); + const MySwal = withReactContent(Swal); + + // 🔹 Ambil userlevelId dari cookies + useEffect(() => { + const ulne = Cookies.get("ulne"); // contoh: "3" + setUserLevelId(ulne ?? null); + }, []); const handleSubmitBanner = (data: any) => { console.log("Banner Data:", data); @@ -26,12 +40,14 @@ export default function ProductPage() {
- - - + {userLevelId !== "3" && ( + + + + )}
diff --git a/app/(admin)/admin/promotion/page.tsx b/app/(admin)/admin/promotion/page.tsx index 3c3d5b5..6b59087 100644 --- a/app/(admin)/admin/promotion/page.tsx +++ b/app/(admin)/admin/promotion/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import ArticleTable from "@/components/table/article-table"; import { Button } from "@/components/ui/button"; import { Plus } from "lucide-react"; @@ -9,10 +9,25 @@ import Link from "next/link"; import ProductTable from "@/components/table/product-table"; import AgentTable from "@/components/table/agent-table"; import PromotionTable from "@/components/table/promotion-table"; +import { useRouter } from "next/navigation"; +import withReactContent from "sweetalert2-react-content"; +import Swal from "sweetalert2"; +import Cookies from "js-cookie"; export default function PromotionPage() { const [openDialog, setOpenDialog] = useState(false); + const [userLevelId, setUserLevelId] = useState(null); + + const router = useRouter(); + const MySwal = withReactContent(Swal); + + // 🔹 Ambil userlevelId dari cookies + useEffect(() => { + const ulne = Cookies.get("ulne"); // contoh: "3" + setUserLevelId(ulne ?? null); + }, []); + const handleSubmitBanner = (data: any) => { console.log("Banner Data:", data); // TODO: kirim data ke API di sini @@ -28,12 +43,14 @@ export default function PromotionPage() {
- - - + {userLevelId !== "3" && ( + + + + )}
diff --git a/app/(admin)/admin/services/page.tsx b/app/(admin)/admin/services/page.tsx new file mode 100644 index 0000000..b46a9d6 --- /dev/null +++ b/app/(admin)/admin/services/page.tsx @@ -0,0 +1,35 @@ +"use client"; + +import { useState } from "react"; +import ArticleTable from "@/components/table/article-table"; +import { Button } from "@/components/ui/button"; +import { Plus } from "lucide-react"; +import { BannerDialog } from "@/components/form/banner-dialog"; +import Link from "next/link"; +import ProductTable from "@/components/table/product-table"; +import ServicesTable from "@/components/table/services-table"; + +export default function ServicesPage() { + const [openDialog, setOpenDialog] = useState(false); + + const handleSubmitBanner = (data: any) => { + console.log("Banner Data:", data); + // TODO: kirim data ke API di sini + }; + + return ( +
+
+
+
+

Services

+
+ +
+ +
+
+
+
+ ); +} diff --git a/app/product/j7-shs/page.tsx b/app/product/j5-ev/page.tsx similarity index 100% rename from app/product/j7-shs/page.tsx rename to app/product/j5-ev/page.tsx diff --git a/app/product/j7-awd/page.tsx b/app/product/j7-shs-p/page.tsx similarity index 100% rename from app/product/j7-awd/page.tsx rename to app/product/j7-shs-p/page.tsx diff --git a/app/product/j8-awd/page.tsx b/app/product/j8-shs/page.tsx similarity index 100% rename from app/product/j8-awd/page.tsx rename to app/product/j8-shs/page.tsx diff --git a/components/landing-page/exterior-j8-awd.tsx b/components/landing-page/exterior-j8-awd.tsx index 5294660..f721e2e 100644 --- a/components/landing-page/exterior-j8-awd.tsx +++ b/components/landing-page/exterior-j8-awd.tsx @@ -76,7 +76,9 @@ export default function ExteriorJ8Awd() { transition={{ duration: 0.6 }} className="text-2xl mt-5 mb-8" > - Jaecoo 8 AWD{" "} + + Jaecoo 8 SHS-P ARDIS + {" "} Teknologi dan Exterior diff --git a/components/landing-page/exterior-shs.tsx b/components/landing-page/exterior-shs.tsx index 17562db..4b1f02e 100644 --- a/components/landing-page/exterior-shs.tsx +++ b/components/landing-page/exterior-shs.tsx @@ -9,7 +9,7 @@ const featuresshs = [ { title: "Rear view mirrors", description: - "The mirrors on the pillars are a discreet but aesthetic design detail of the Jaecoo J7 SHS. Their contrasting inserts harmoniously resonate with other accent touches of the exterior.", + "The mirrors on the pillars are a discreet but aesthetic design detail of the Jaecoo J5 EV. Their contrasting inserts harmoniously resonate with other accent touches of the exterior.", image: "/ex-shs3.png", }, { @@ -53,7 +53,7 @@ export default function ExteriorShs() { transition={{ duration: 0.6 }} className="text-2xl mt-5 mb-8" > - Jaecoo 7 SHS{" "} + Jaecoo 5 EV{" "} Teknologi dan Exterior diff --git a/components/landing-page/exterior.tsx b/components/landing-page/exterior.tsx index f066687..d628f3e 100644 --- a/components/landing-page/exterior.tsx +++ b/components/landing-page/exterior.tsx @@ -53,7 +53,7 @@ export default function Exterior() { transition={{ duration: 0.6 }} className="text-2xl mt-5 mb-8" > - Jaecoo 7 AWD{" "} + Jaecoo 7 SHS-P{" "} Teknologi dan Exterior diff --git a/components/landing-page/features-and-specifications-j8.tsx b/components/landing-page/features-and-specifications-j8.tsx index 89c782e..ab916ed 100644 --- a/components/landing-page/features-and-specifications-j8.tsx +++ b/components/landing-page/features-and-specifications-j8.tsx @@ -6,7 +6,10 @@ export default function FeaturesAndSpecificationsJ8() { return (

- Jaecoo 8 AWD Fitur + + Jaecoo 8 SHS-P ARDIS + {" "} + Fitur

@@ -39,7 +42,9 @@ export default function FeaturesAndSpecificationsJ8() { />

- Jaecoo 8 AWD{" "} + + Jaecoo 8 SHS-P ARDIS + {" "} Spesifikasi

diff --git a/components/landing-page/features-and-specifications-shs.tsx b/components/landing-page/features-and-specifications-shs.tsx index d6864ef..3344d67 100644 --- a/components/landing-page/features-and-specifications-shs.tsx +++ b/components/landing-page/features-and-specifications-shs.tsx @@ -6,7 +6,7 @@ export default function FeaturesAndSpecificationsShs() { return (

- Jaecoo 7 SHS Fitur + Jaecoo 5 EV Fitur

@@ -38,7 +38,7 @@ export default function FeaturesAndSpecificationsShs() { />

- Jaecoo 7 SHS{" "} + Jaecoo 5 EV{" "} Spesifikasi

diff --git a/components/landing-page/features-and-specifications.tsx b/components/landing-page/features-and-specifications.tsx index 2d9ab00..46b6951 100644 --- a/components/landing-page/features-and-specifications.tsx +++ b/components/landing-page/features-and-specifications.tsx @@ -6,7 +6,8 @@ export default function FeaturesAndSpecifications() { return (

- Jaecoo 7 AWD Fitur + Jaecoo 7 SHS-P{" "} + Fitur

@@ -38,7 +39,7 @@ export default function FeaturesAndSpecifications() { />

- Jaecoo 7 AWD{" "} + Jaecoo 7 SHS-P{" "} Spesifikasi

diff --git a/components/landing-page/header-after-sales.tsx b/components/landing-page/header-after-sales.tsx index 8386312..7dbf3e0 100644 --- a/components/landing-page/header-after-sales.tsx +++ b/components/landing-page/header-after-sales.tsx @@ -8,7 +8,7 @@ import { useState } from "react"; export default function HeaderAfterSalesServices() { const cars = [ { - title: "JAECOO J7 AWD", + title: "JAECOO J7 SHS-PV-P", image: "/j7-awd-nobg.png", price: "Rp 549.000.000", oldPrice: "Rp 544.000.000", @@ -18,7 +18,7 @@ export default function HeaderAfterSalesServices() { display: `14.8"`, }, { - title: "JAECOO J7 SHS", + title: "JAECOO J5 EV", image: "/j7-shs-nobg.png", price: "Rp 599.000.000", oldPrice: "Rp 594.000.000", @@ -28,7 +28,7 @@ export default function HeaderAfterSalesServices() { display: `14.8"`, }, { - title: "JAECOO J8 AWD", + title: "JAECOO J8 SHS-P ARDIS", image: "/j8-awd-nobg.png", price: "Rp 812.000.000", oldPrice: "Rp 807.000.000", diff --git a/components/landing-page/header-price.tsx b/components/landing-page/header-price.tsx index 70c8221..d12dd46 100644 --- a/components/landing-page/header-price.tsx +++ b/components/landing-page/header-price.tsx @@ -19,31 +19,36 @@ export default function HeaderPriceInformation() { const [open, setOpen] = useState(false); const cars = [ { - title: "JAECOO J7 AWD", + title: "JAECOO J7 SHS-P", image: "/j7-awd-nobg.png", - price: "Rp 549.000.000", - oldPrice: "Rp 544.000.000", + price: "Rp 509.900.000", + oldPrice: "Rp 509.900.000", capacity: "18.3kWh", + power: "-", + torque: "310 N.m", wheels: `19"`, seats: "Leather", display: `14.8"`, }, { - title: "JAECOO J7 SHS", + title: "JAECOO J5 EV", image: "/j7-shs-nobg.png", - price: "Rp 599.000.000", - oldPrice: "Rp 594.000.000", - capacity: "18.3kWh", + price: "Rp 299.900.000", + oldPrice: "Rp 299.900.000", + capacity: "60.9kWh", + power: "155kW", + torque: "288Nm", wheels: `19"`, seats: "Leather", display: `14.8"`, }, { - title: "JAECOO J8 AWD", + title: "JAECOO J8 SHS-P ARDIS", image: "/j8-awd-nobg.png", price: "Rp 812.000.000", - oldPrice: "Rp 807.000.000", - capacity: "18.3kWh", + oldPrice: "Rp 828.000.000", + capacity: "34,46kWh", + torque: "650Nm", wheels: `19"`, seats: "Leather", display: `14.8"`, @@ -119,10 +124,10 @@ export default function HeaderPriceInformation() {
-

+ {/*

*Save Rp 5.000.000 on the previous driveway price of{" "} {car.oldPrice}. Offer ends 31st August 2025. -

+

*/}
- {car.wheels}{" "} - Alloy Wheels + {car.power}{" "} + Max Power
@@ -167,16 +172,28 @@ export default function HeaderPriceInformation() { xmlns="http://www.w3.org/2000/svg" width="24" height="24" - viewBox="0 0 512 512" + viewBox="0 0 48 48" > +
- {car.seats}{" "} - Seats + {car.torque}{" "} + Torque
diff --git a/components/landing-page/header.tsx b/components/landing-page/header.tsx index 9226d43..6095e7c 100644 --- a/components/landing-page/header.tsx +++ b/components/landing-page/header.tsx @@ -57,7 +57,7 @@ export default function Header() { transition={{ duration: 0.8, ease: "easeOut" }} className="text-2xl sm:text-3xl md:text-5xl font-bold text-black mb-4" > - JAECOO J7 AWD + JAECOO J7 SHS-P - Jaecoo 8 AWD{" "} + + Jaecoo 8 SHS-P ARDIS + {" "} Interior diff --git a/components/landing-page/interior-shs.tsx b/components/landing-page/interior-shs.tsx index 3866714..298b8e9 100644 --- a/components/landing-page/interior-shs.tsx +++ b/components/landing-page/interior-shs.tsx @@ -67,7 +67,7 @@ export default function InteriorShs() { animate={inView ? { opacity: 1, y: 0 } : {}} transition={{ duration: 0.6 }} > - Jaecoo 7 SHS{" "} + Jaecoo 5 EV{" "} Interior diff --git a/components/landing-page/interior.tsx b/components/landing-page/interior.tsx index 5d47453..8eb8098 100644 --- a/components/landing-page/interior.tsx +++ b/components/landing-page/interior.tsx @@ -61,7 +61,7 @@ export default function Interior() { animate={inView ? { opacity: 1, y: 0 } : {}} transition={{ duration: 0.6 }} > - Jaecoo 7 AWD{" "} + Jaecoo 7 SHS-P{" "} Interior diff --git a/components/landing-page/items.tsx b/components/landing-page/items.tsx index 5b7ca9c..44b54e6 100644 --- a/components/landing-page/items.tsx +++ b/components/landing-page/items.tsx @@ -18,19 +18,19 @@ import { useState } from "react"; const items = [ { image: "/new-car2.png", - title: "JAECOO J7 AWD", + title: "JAECOO J7 SHS-P", description: "DELICATE OFF-ROAD SUV", link: "/product/j7-awd", }, { image: "/new-car1.png", - title: "JAECOO J7 SHS", + title: "JAECOO J5 EV", description: "SUPER HYBRID SYSTEM = SUPER HEV + EV", link: "/product/j7-shs", }, { image: "/new-car3.png", - title: "JAECOO J8 AWD", + title: "JAECOO J8 SHS-P ARDIS", description: "FIRST CLASS OFF-ROAD", link: "/product/j8-awd", }, diff --git a/components/landing-page/navbar.tsx b/components/landing-page/navbar.tsx index 1cb1eed..1eecf48 100644 --- a/components/landing-page/navbar.tsx +++ b/components/landing-page/navbar.tsx @@ -47,19 +47,19 @@ export default function Navbar() { const produkList = [ { - name: "JAECOO J7 AWD", + name: "JAECOO J7 SHS-P", img: "/j7awd.png", - link: "/product/j7-awd", + link: "/product/j7-shs-p", }, { - name: "JAECOO J7 SHS", + name: "JAECOO J5 EV", img: "/j7shs.png", - link: "/product/j7-shs", + link: "/product/j5-ev", }, { - name: "JAECOO J8 AWD", + name: "JAECOO J8 SHS-P ARDIS", img: "/j8awd.png", - link: "/product/j8-awd", + link: "/product/j8-shs", }, ]; const priceList = [ diff --git a/components/landing-page/retracting-sidedar.tsx b/components/landing-page/retracting-sidedar.tsx index bd915b6..bbed730 100644 --- a/components/landing-page/retracting-sidedar.tsx +++ b/components/landing-page/retracting-sidedar.tsx @@ -84,7 +84,7 @@ const sidebarSections = [ height="18" /> ), - link: "/admin/costumer-support", + link: "/admin/costumer-service", }, { title: "Manajemen User", diff --git a/components/main/dashboard/dashboard-container.tsx b/components/main/dashboard/dashboard-container.tsx index c1ee4ee..905fa78 100644 --- a/components/main/dashboard/dashboard-container.tsx +++ b/components/main/dashboard/dashboard-container.tsx @@ -102,7 +102,7 @@ export default function DashboardContainer() { no: 3, tanggal: "09/11/2024", jenis: "Produk", - judul: "JAECOO J7 AWD Update", + judul: "JAECOO J7 SHS-P Update", status: "Disetujui", }, { @@ -131,12 +131,12 @@ export default function DashboardContainer() { const notifications = [ { icon: "✅", - text: 'Upload "JAECOO J7 AWD Update" telah disetujui oleh Admin Manager', + text: 'Upload "JAECOO J7 SHS-P Update" telah disetujui oleh Admin Manager', time: "2 jam yang lalu", }, { icon: "❌", - text: 'Upload "Brosur JAECOO J8" ditolak. Alasan: Resolusi gambar terlalu rendah.', + text: 'Upload "Brosur JAECOO J8 SHS-P ARDIS" ditolak. Alasan: Resolusi gambar terlalu rendah.', time: "2 jam yang lalu", }, { @@ -224,7 +224,7 @@ export default function DashboardContainer() { }; const res = await getUserLevelDataStat( getDate(postContentDate.startDate), - getDate(postContentDate.endDate) + getDate(postContentDate.endDate), ); setPostCount(getTableNumber(10, res?.data?.data)); } diff --git a/components/table/agent-table.tsx b/components/table/agent-table.tsx index d09f6dd..033aaa9 100644 --- a/components/table/agent-table.tsx +++ b/components/table/agent-table.tsx @@ -294,7 +294,7 @@ export default function AgentTable() { return cellValue; } }, - [article, page] + [article, page], ); let typingTimer: NodeJS.Timeout; @@ -523,7 +523,7 @@ export default function AgentTable() { ✕ -

JAEC00 J7 AWD

+

JAEC00 J7 SHS-P

DELICATE OFF-ROAD SUV

{/* Status badge */} diff --git a/components/table/article-table.tsx b/components/table/article-table.tsx index 5974502..9815a47 100644 --- a/components/table/article-table.tsx +++ b/components/table/article-table.tsx @@ -47,7 +47,7 @@ import { import CustomPagination from "../layout/custom-pagination"; import { EditBannerDialog } from "../form/banner-edit-dialog"; import { deleteBanner, getBannerData, updateBanner } from "@/service/banner"; -import { CheckCheck } from "lucide-react"; +import { CheckCheck, Eye } from "lucide-react"; const columns = [ { name: "No", uid: "no" }, @@ -170,8 +170,20 @@ export default function ArticleTable() { const [openEditDialog, setOpenEditDialog] = useState(false); const [selectedBanner, setSelectedBanner] = useState(null); const [openPreview, setOpenPreview] = useState(false); + const [openViewDialog, setOpenViewDialog] = useState(false); + const [viewBanner, setViewBanner] = useState(null); + const [openApproverHistory, setOpenApproverHistory] = useState(false); + + const handleView = (item: any) => { + setViewBanner(item); + setOpenViewDialog(true); + }; const [previewImage, setPreviewImage] = useState(null); + const handleOpenApproverHistory = () => { + setOpenApproverHistory(true); + }; + const handleEdit = (item: any) => { setSelectedBanner({ id: item.id, @@ -211,19 +223,7 @@ export default function ArticleTable() { switch (columnKey) { case "isPublish": - return ( - // - //
- // {article.status} - //
- //
-

{article.isPublish ? "Publish" : "Draft"}

- ); + return

{article.isPublish ? "Publish" : "Draft"}

; case "isBanner": return

{article.isBanner ? "Ya" : "Tidak"}

; case "createdAt": @@ -305,7 +305,7 @@ export default function ArticleTable() { return cellValue; } }, - [article, page] + [article, page], ); let typingTimer: NodeJS.Timeout; @@ -424,10 +424,10 @@ export default function ArticleTable() { variant="ghost" size="sm" className="text-[#0F6C75] hover:bg-transparent hover:underline p-0" - // onClick={() => handleEdit(item)} + onClick={() => handleView(item)} > - - Approve + + Lihat
)} + {openViewDialog && viewBanner && ( +
setOpenViewDialog(false)} + > +
e.stopPropagation()} + > + {/* HEADER */} +
+ + +

Detail Banner

+ + {/* Badge */} +
+ + {viewBanner.status} + + + + Banner + + + + {viewBanner.position} + +
+
+ + {/* BODY */} +
+ {/* JUDUL */} +
+ +
+ {viewBanner.title} +
+
+ + {/* IMAGE */} +
+ +
+ {viewBanner.thumbnail_url ? ( + {viewBanner.title} + ) : ( +
+ No Image +
+ )} +
+
+ + {/* TIMELINE */} +
+

+ Status Timeline +

+ +
+
+
+ +
+
+

+ Diupload oleh {viewBanner.createdByName} +

+

+ {convertDateFormat(viewBanner.created_at)} WIB +

+
+
+ +
+
+ ⏳ +
+
+

+ Menunggu disetujui oleh Approver +

+

+ {convertDateFormat(viewBanner.updated_at)} WIB +

+
+
+ + +
+
+
+ + {/* FOOTER */} +
+ + +
+ + +
+
+
+
+ )} + {openApproverHistory && ( +
setOpenApproverHistory(false)} + > +
e.stopPropagation()} + > + {/* HEADER */} +
+ + +

Approver History

+ +
+ + Menunggu + + + Banner + + + 1 + +
+
+ + {/* BODY */} +
+ {/* LEFT TIMELINE */} +
+ {/* Upload */} +
+ + Upload + +
+
+ + {/* Diterima */} +
+

Diterima

+ + Direview oleh: approver-jaecoo1 + +
+ +
+ + {/* Pending */} +
+

Pending

+ + Direview oleh: approver-jaecoo1 + +
+
+ + {/* ARROW */} +
+ > + > +
+ + {/* RIGHT NOTES */} +
+
+
+ Catatan: +
+
+ +
+
+ Catatan: +
+
+
+
+ + {/* FOOTER */} +
+ +
+
+
+ )} ); } diff --git a/components/table/costumer-service-table.tsx b/components/table/costumer-service-table.tsx new file mode 100644 index 0000000..15cb47c --- /dev/null +++ b/components/table/costumer-service-table.tsx @@ -0,0 +1,505 @@ +"use client"; +import { + BannerIcon, + CopyIcon, + CreateIconIon, + DeleteIcon, + DotsYIcon, + EyeIconMdi, + SearchIcon, +} from "@/components/icons"; +import { close, error, loading, success, successToast } from "@/config/swal"; +import { Article } from "@/types/globals"; +import { convertDateFormat } from "@/utils/global"; +import Link from "next/link"; +import { Key, useCallback, useEffect, useState } from "react"; +import Swal from "sweetalert2"; +import withReactContent from "sweetalert2-react-content"; +import Cookies from "js-cookie"; +import { + deleteArticle, + getArticleByCategory, + getArticlePagination, + updateIsBannerArticle, +} from "@/service/article"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "../ui/dropdown-menu"; +import { Button } from "../ui/button"; +import { Input } from "../ui/input"; +import { + Select, + SelectTrigger, + SelectValue, + SelectContent, + SelectItem, +} from "@/components/ui/select"; +import { + Table, + TableHeader, + TableBody, + TableRow, + TableHead, + TableCell, +} from "@/components/ui/table"; +import CustomPagination from "../layout/custom-pagination"; +import { EditBannerDialog } from "../form/banner-edit-dialog"; +import { deleteProduct, getProductPagination } from "@/service/product"; +import { CheckCheck, Plus } from "lucide-react"; + +import { + Card, + CardHeader, + CardTitle, + CardDescription, + CardContent, + CardFooter, +} from "../ui/card"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "../ui/tabs"; +import { Label } from "../ui/label"; +import { useRouter } from "next/navigation"; + +const columns = [ + { name: "No", uid: "no" }, + { name: "Judul", uid: "title" }, + { name: "Banner", uid: "isBanner" }, + { name: "Kategori", uid: "category" }, + { name: "Tanggal Unggah", uid: "createdAt" }, + { name: "Kreator", uid: "createdByName" }, + { name: "Status", uid: "isPublish" }, + { name: "Aksi", uid: "actions" }, +]; +const columnsOtherRole = [ + { name: "No", uid: "no" }, + { name: "Judul", uid: "title" }, + { name: "Kategori", uid: "category" }, + { name: "Tanggal Unggah", uid: "createdAt" }, + { name: "Kreator", uid: "createdByName" }, + { name: "Status", uid: "isPublish" }, + { name: "Aksi", uid: "actions" }, +]; + +// interface Category { +// id: number; +// title: string; +// } + +export default function CostumerServiceTable() { + const MySwal = withReactContent(Swal); + const username = Cookies.get("username"); + const userId = Cookies.get("uie"); + + const [page, setPage] = useState(1); + const [totalPage, setTotalPage] = useState(1); + const [article, setArticle] = useState([]); + const [showData, setShowData] = useState("10"); + const [search, setSearch] = useState(""); + const [categories, setCategories] = useState([]); + const [selectedCategories, setSelectedCategories] = useState(""); + const [startDateValue, setStartDateValue] = useState({ + startDate: null, + endDate: null, + }); + + const [userLevelId, setUserLevelId] = useState(null); + + const router = useRouter(); + + // 🔹 Ambil userlevelId dari cookies + useEffect(() => { + const ulne = Cookies.get("ulne"); // contoh: "3" + setUserLevelId(ulne ?? null); + }, []); + + useEffect(() => { + initState(); + getCategories(); + }, []); + + async function getCategories() { + const res = await getArticleByCategory(); + const data = res?.data?.data; + setCategories(data); + } + + const initState = useCallback(async () => { + loading(); + const req = { + limit: showData, + page: page, + search: search, + }; + const res = await getProductPagination(req); + await getTableNumber(parseInt(showData), res.data?.data); + setTotalPage(res?.data?.meta?.totalPage); + close(); + }, [page]); + + const getTableNumber = async (limit: number, data: Article[]) => { + if (data) { + const startIndex = limit * (page - 1); + let iterate = 0; + const newData = data.map((value: any) => { + iterate++; + value.no = startIndex + iterate; + return value; + }); + setArticle(newData); + } else { + setArticle([]); + } + }; + + async function doDelete(id: any) { + // loading(); + const resDelete = await deleteProduct(id); + + if (resDelete?.error) { + error(resDelete.message); + return false; + } + close(); + success("Berhasil Hapus"); + initState(); + } + + const handleDelete = (id: any) => { + MySwal.fire({ + title: "Hapus Data", + icon: "warning", + showCancelButton: true, + cancelButtonColor: "#3085d6", + confirmButtonColor: "#d33", + confirmButtonText: "Hapus", + }).then((result) => { + if (result.isConfirmed) { + doDelete(id); + } + }); + }; + + const handleBanner = async (id: number, status: boolean) => { + const res = await updateIsBannerArticle(id, status); + if (res?.error) { + error(res?.message); + return false; + } + initState(); + }; + + const [openEditDialog, setOpenEditDialog] = useState(false); + const [selectedBanner, setSelectedBanner] = useState(null); + const [openPreview, setOpenPreview] = useState(false); + const [previewImage, setPreviewImage] = useState(null); + + const handleUpdateBanner = (data: any) => { + console.log("Updated banner data:", data); + // TODO: panggil API update di sini + // lalu refresh tabel + }; + + const handlePreview = (imgUrl: string) => { + setPreviewImage(imgUrl); + setOpenPreview(true); + }; + + const copyUrlArticle = async (id: number, slug: string) => { + const url = + `${window.location.protocol}//${window.location.host}` + + "/news/detail/" + + `${id}-${slug}`; + try { + await navigator.clipboard.writeText(url); + successToast("Success", "Article Copy to Clipboard"); + setTimeout(() => {}, 1500); + } catch (err) { + ("Failed to copy!"); + } + }; + + const renderCell = useCallback( + (article: any, columnKey: Key) => { + const cellValue = article[columnKey as keyof any]; + + switch (columnKey) { + case "isPublish": + return ( + // + //
+ // {article.status} + //
+ //
+

{article.isPublish ? "Publish" : "Draft"}

+ ); + case "isBanner": + return

{article.isBanner ? "Ya" : "Tidak"}

; + case "createdAt": + return

{convertDateFormat(article.createdAt)}

; + case "category": + return ( +

+ {article?.categories?.map((list: any) => list.title).join(", ") + + " "} +

+ ); + + case "actions": + return ( +
+ + + + + + copyUrlArticle(article.id, article.slug)} + > + + Copy Url Article + + + + + + Detail + + + + {(username === "admin-mabes" || + Number(userId) === article.createdById) && ( + + + + Edit + + + )} + + {username === "admin-mabes" && ( + + handleBanner(article.id, !article.isBanner) + } + > + + {article.isBanner + ? "Hapus dari Banner" + : "Jadikan Banner"} + + )} + + {(username === "admin-mabes" || + Number(userId) === article.createdById) && ( + handleDelete(article.id)}> + + Delete + + )} + + +
+ ); + + default: + return cellValue; + } + }, + [article, page], + ); + + let typingTimer: NodeJS.Timeout; + const doneTypingInterval = 1500; + + const handleKeyUp = () => { + clearTimeout(typingTimer); + typingTimer = setTimeout(doneTyping, doneTypingInterval); + }; + + const handleKeyDown = () => { + clearTimeout(typingTimer); + }; + + async function doneTyping() { + setPage(1); + initState(); + } + + return ( + <> +
+
+ {/* Header */} + + + + After Sales + + + Sales + + + {userLevelId !== "3" && ( + + + + )} + + +
+ Daftar After Sales +
+ + {/* FOOTER PAGINATION */} +
+

+ Menampilkan {article.length} dari {article.length} data +

+
+ +

+ Halaman {page} dari {totalPage} +

+ +
+
+
+ +
+ Daftar Sales +
+ + {/* FOOTER PAGINATION */} +
+

+ Menampilkan {article.length} dari {article.length} data +

+
+ +

+ Halaman {page} dari {totalPage} +

+ +
+
+
+
+
+
+ + {/* Preview Dialog */} + {openPreview && ( +
setOpenPreview(false)} + > +
e.stopPropagation()} + > + {/* HEADER */} +
+ {/* Tombol close */} + + +

JAEC00 J7 SHS-P

+

DELICATE OFF-ROAD SUV

+ + {/* Status badge */} +
+ + Menunggu + + + 1 + +
+
+ + {/* IMAGE PREVIEW */} +
+ Preview +
+ + {/* FOOTER */} +
+ +
+
+
+ )} + + ); +} diff --git a/components/table/product-table.tsx b/components/table/product-table.tsx index 1d173bb..2491a37 100644 --- a/components/table/product-table.tsx +++ b/components/table/product-table.tsx @@ -298,7 +298,7 @@ export default function ProductTable() { return cellValue; } }, - [article, page] + [article, page], ); let typingTimer: NodeJS.Timeout; @@ -522,7 +522,7 @@ export default function ProductTable() { ✕ -

JAEC00 J7 AWD

+

JAEC00 J7 SHS-P

DELICATE OFF-ROAD SUV

{/* Status badge */} diff --git a/components/table/promotion-table.tsx b/components/table/promotion-table.tsx index 577f103..b749f9e 100644 --- a/components/table/promotion-table.tsx +++ b/components/table/promotion-table.tsx @@ -296,7 +296,7 @@ export default function PromotionTable() { return cellValue; } }, - [article, page] + [article, page], ); let typingTimer: NodeJS.Timeout; @@ -499,7 +499,7 @@ export default function PromotionTable() { ✕ -

JAEC00 J7 AWD

+

JAEC00 J7 SHS-P

DELICATE OFF-ROAD SUV

{/* Status badge */} diff --git a/components/table/services-table.tsx b/components/table/services-table.tsx new file mode 100644 index 0000000..e9ac666 --- /dev/null +++ b/components/table/services-table.tsx @@ -0,0 +1,508 @@ +"use client"; +import { + BannerIcon, + CopyIcon, + CreateIconIon, + DeleteIcon, + DotsYIcon, + EyeIconMdi, + SearchIcon, +} from "@/components/icons"; +import { close, error, loading, success, successToast } from "@/config/swal"; +import { Article } from "@/types/globals"; +import { convertDateFormat } from "@/utils/global"; +import Link from "next/link"; +import { Key, useCallback, useEffect, useState } from "react"; +import Swal from "sweetalert2"; +import withReactContent from "sweetalert2-react-content"; +import Cookies from "js-cookie"; +import { + deleteArticle, + getArticleByCategory, + getArticlePagination, + updateIsBannerArticle, +} from "@/service/article"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "../ui/dropdown-menu"; +import { Button } from "../ui/button"; +import { Input } from "../ui/input"; +import { + Select, + SelectTrigger, + SelectValue, + SelectContent, + SelectItem, +} from "@/components/ui/select"; +import { + Table, + TableHeader, + TableBody, + TableRow, + TableHead, + TableCell, +} from "@/components/ui/table"; +import CustomPagination from "../layout/custom-pagination"; +import { EditBannerDialog } from "../form/banner-edit-dialog"; +import { deleteProduct, getProductPagination } from "@/service/product"; +import { CheckCheck, Plus } from "lucide-react"; + +import { + Card, + CardHeader, + CardTitle, + CardDescription, + CardContent, + CardFooter, +} from "../ui/card"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "../ui/tabs"; +import { Label } from "../ui/label"; +import { useRouter } from "next/navigation"; + +const columns = [ + { name: "No", uid: "no" }, + { name: "Judul", uid: "title" }, + { name: "Banner", uid: "isBanner" }, + { name: "Kategori", uid: "category" }, + { name: "Tanggal Unggah", uid: "createdAt" }, + { name: "Kreator", uid: "createdByName" }, + { name: "Status", uid: "isPublish" }, + { name: "Aksi", uid: "actions" }, +]; +const columnsOtherRole = [ + { name: "No", uid: "no" }, + { name: "Judul", uid: "title" }, + { name: "Kategori", uid: "category" }, + { name: "Tanggal Unggah", uid: "createdAt" }, + { name: "Kreator", uid: "createdByName" }, + { name: "Status", uid: "isPublish" }, + { name: "Aksi", uid: "actions" }, +]; + +// interface Category { +// id: number; +// title: string; +// } + +export default function ServicesTable() { + const MySwal = withReactContent(Swal); + const username = Cookies.get("username"); + const userId = Cookies.get("uie"); + + const [page, setPage] = useState(1); + const [totalPage, setTotalPage] = useState(1); + const [article, setArticle] = useState([]); + const [showData, setShowData] = useState("10"); + const [search, setSearch] = useState(""); + const [categories, setCategories] = useState([]); + const [selectedCategories, setSelectedCategories] = useState(""); + const [startDateValue, setStartDateValue] = useState({ + startDate: null, + endDate: null, + }); + + const [userLevelId, setUserLevelId] = useState(null); + + const router = useRouter(); + + // 🔹 Ambil userlevelId dari cookies + useEffect(() => { + const ulne = Cookies.get("ulne"); // contoh: "3" + setUserLevelId(ulne ?? null); + }, []); + + useEffect(() => { + initState(); + getCategories(); + }, []); + + async function getCategories() { + const res = await getArticleByCategory(); + const data = res?.data?.data; + setCategories(data); + } + + const initState = useCallback(async () => { + loading(); + const req = { + limit: showData, + page: page, + search: search, + }; + const res = await getProductPagination(req); + await getTableNumber(parseInt(showData), res.data?.data); + setTotalPage(res?.data?.meta?.totalPage); + close(); + }, [page]); + + const getTableNumber = async (limit: number, data: Article[]) => { + if (data) { + const startIndex = limit * (page - 1); + let iterate = 0; + const newData = data.map((value: any) => { + iterate++; + value.no = startIndex + iterate; + return value; + }); + setArticle(newData); + } else { + setArticle([]); + } + }; + + async function doDelete(id: any) { + // loading(); + const resDelete = await deleteProduct(id); + + if (resDelete?.error) { + error(resDelete.message); + return false; + } + close(); + success("Berhasil Hapus"); + initState(); + } + + const handleDelete = (id: any) => { + MySwal.fire({ + title: "Hapus Data", + icon: "warning", + showCancelButton: true, + cancelButtonColor: "#3085d6", + confirmButtonColor: "#d33", + confirmButtonText: "Hapus", + }).then((result) => { + if (result.isConfirmed) { + doDelete(id); + } + }); + }; + + const handleBanner = async (id: number, status: boolean) => { + const res = await updateIsBannerArticle(id, status); + if (res?.error) { + error(res?.message); + return false; + } + initState(); + }; + + const [openEditDialog, setOpenEditDialog] = useState(false); + const [selectedBanner, setSelectedBanner] = useState(null); + const [openPreview, setOpenPreview] = useState(false); + const [previewImage, setPreviewImage] = useState(null); + + const handleUpdateBanner = (data: any) => { + console.log("Updated banner data:", data); + // TODO: panggil API update di sini + // lalu refresh tabel + }; + + const handlePreview = (imgUrl: string) => { + setPreviewImage(imgUrl); + setOpenPreview(true); + }; + + const copyUrlArticle = async (id: number, slug: string) => { + const url = + `${window.location.protocol}//${window.location.host}` + + "/news/detail/" + + `${id}-${slug}`; + try { + await navigator.clipboard.writeText(url); + successToast("Success", "Article Copy to Clipboard"); + setTimeout(() => {}, 1500); + } catch (err) { + ("Failed to copy!"); + } + }; + + const renderCell = useCallback( + (article: any, columnKey: Key) => { + const cellValue = article[columnKey as keyof any]; + + switch (columnKey) { + case "isPublish": + return ( + // + //
+ // {article.status} + //
+ //
+

{article.isPublish ? "Publish" : "Draft"}

+ ); + case "isBanner": + return

{article.isBanner ? "Ya" : "Tidak"}

; + case "createdAt": + return

{convertDateFormat(article.createdAt)}

; + case "category": + return ( +

+ {article?.categories?.map((list: any) => list.title).join(", ") + + " "} +

+ ); + + case "actions": + return ( +
+ + + + + + copyUrlArticle(article.id, article.slug)} + > + + Copy Url Article + + + + + + Detail + + + + {(username === "admin-mabes" || + Number(userId) === article.createdById) && ( + + + + Edit + + + )} + + {username === "admin-mabes" && ( + + handleBanner(article.id, !article.isBanner) + } + > + + {article.isBanner + ? "Hapus dari Banner" + : "Jadikan Banner"} + + )} + + {(username === "admin-mabes" || + Number(userId) === article.createdById) && ( + handleDelete(article.id)}> + + Delete + + )} + + +
+ ); + + default: + return cellValue; + } + }, + [article, page], + ); + + let typingTimer: NodeJS.Timeout; + const doneTypingInterval = 1500; + + const handleKeyUp = () => { + clearTimeout(typingTimer); + typingTimer = setTimeout(doneTyping, doneTypingInterval); + }; + + const handleKeyDown = () => { + clearTimeout(typingTimer); + }; + + async function doneTyping() { + setPage(1); + initState(); + } + + return ( + <> +
+
+ {/* Header */} + + + + Program Services + + + After Sales + + + {userLevelId !== "3" && ( + + + + )} + + +
+ Daftar Services +
+ + {/* FOOTER PAGINATION */} +
+

+ Menampilkan {article.length} dari {article.length} data +

+
+ +

+ Halaman {page} dari {totalPage} +

+ +
+
+
+ +
+ Daftar After Sales +
+ + {/* FOOTER PAGINATION */} +
+

+ Menampilkan {article.length} dari {article.length} data +

+
+ +

+ Halaman {page} dari {totalPage} +

+ +
+
+
+
+
+
+ + {/* Preview Dialog */} + {openPreview && ( +
setOpenPreview(false)} + > +
e.stopPropagation()} + > + {/* HEADER */} +
+ {/* Tombol close */} + + +

JAEC00 J7 SHS-P

+

DELICATE OFF-ROAD SUV

+ + {/* Status badge */} +
+ + Menunggu + + + 1 + +
+
+ + {/* IMAGE PREVIEW */} +
+ Preview +
+ + {/* FOOTER */} +
+ +
+
+
+ )} + + ); +} diff --git a/components/ui/tabs.tsx b/components/ui/tabs.tsx new file mode 100644 index 0000000..497ba5e --- /dev/null +++ b/components/ui/tabs.tsx @@ -0,0 +1,66 @@ +"use client" + +import * as React from "react" +import * as TabsPrimitive from "@radix-ui/react-tabs" + +import { cn } from "@/lib/utils" + +function Tabs({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function TabsList({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function TabsTrigger({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function TabsContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { Tabs, TabsList, TabsTrigger, TabsContent } diff --git a/package-lock.json b/package-lock.json index 65bb0a0..c5826f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "@radix-ui/react-select": "^2.2.5", "@radix-ui/react-slot": "^1.2.3", "@radix-ui/react-switch": "^1.2.5", + "@radix-ui/react-tabs": "^1.1.13", "@types/js-cookie": "^3.0.6", "apexcharts": "^4.7.0", "axios": "^1.10.0", @@ -2435,6 +2436,93 @@ } } }, + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz", + "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==" + }, + "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-presence": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", + "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz", + "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-use-callback-ref": { "version": "1.1.1", "license": "MIT", diff --git a/package.json b/package.json index 4820200..b84f453 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "@radix-ui/react-select": "^2.2.5", "@radix-ui/react-slot": "^1.2.3", "@radix-ui/react-switch": "^1.2.5", + "@radix-ui/react-tabs": "^1.1.13", "@types/js-cookie": "^3.0.6", "apexcharts": "^4.7.0", "axios": "^1.10.0",