feat:spesific target mapping
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Rama Priyanto 2026-04-17 18:18:39 +07:00
parent 1a87749950
commit b7d0f00def
3 changed files with 387 additions and 1 deletions

View File

@ -0,0 +1,16 @@
"use client"
import SpesificTargetMappingTable from "@/components/table/spesific-target-mapping/spesific-target-mapping-table"
import dynamic from "next/dynamic"
const Navbar = dynamic(() => import("@/components/ui/navbar"), {
ssr: false,
})
export default function SpesificTargetMapping() {
return (
<div className="flex w-full flex-col gap-4">
<Navbar title="Spesific Target Mapping" />
<SpesificTargetMappingTable />
</div>
)
}

View File

@ -0,0 +1,370 @@
"use client"
import { ReloadIcon } from "@/components/icons"
import { Button } from "@/components/ui/button"
import { Checkbox } from "@/components/ui/checkbox"
import { Input } from "@/components/ui/input"
import {
InputGroup,
InputGroupAddon,
InputGroupInput,
} from "@/components/ui/input-group"
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
import {
Table,
TableBody,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table"
import { ChevronLeft, ChevronRight, SearchIcon } from "lucide-react"
import { useEffect, useState } from "react"
const dummyProxy = [
{ id: 1, value: "Jakarta" },
{ id: 2, value: "Bandung" },
{ id: 3, value: "Surabaya" },
{ id: 4, value: "Medan" },
]
const dummyStatus = [
{ id: 1, value: "Negative" },
{ id: 2, value: "Positive" },
{ id: 3, value: "Neutral" },
]
const dummyData = [
{
id: "1",
identifier: "MyUsername123",
proxy: "Jakarta",
sentiment: 1,
},
{
id: "2",
identifier: "MyUsername12223",
proxy: "Bandung",
sentiment: 2,
},
{
id: "3",
identifier: "MyUsername1132123",
proxy: "Jakarta",
sentiment: 3,
},
{
id: "4",
identifier: "MyUsername422123",
proxy: "Medan",
sentiment: 4,
},
{
id: "5",
identifier: "12MyUsername422123",
proxy: "Surabaya",
sentiment: 1,
},
]
const dummyDataTarget = [
{
id: "1",
name: "POLRI - DIV Humas",
status: 1,
},
{
id: "2",
name: "POLRI - Korlantas",
status: 2,
},
{
id: "3",
name: "TNI",
status: 3,
},
{
id: "4",
name: "DPR",
status: 3,
},
]
export default function SpesificTargetMappingTable() {
const [selectedStatus, setSelectedStatus] = useState("")
const [selectedLocation, setSelectedLocation] = useState("")
const [search, setSearch] = useState("")
const [limit, setLimit] = useState("5")
const [page, setPage] = useState(1)
// const [totalPage, setTotalPage] = useState(1)
const [selectedDataTable, setSelectedDataTable] = useState<string[]>([])
const getData = async () => {
const req = {
search: search,
sentiment: selectedStatus,
proxy: selectedLocation,
page: page,
limit: limit,
}
console.log("request", req)
}
useEffect(() => {
getData()
}, [page, limit])
const resetFilter = () => {
setSelectedLocation("")
setSelectedStatus("")
setSearch("")
setPage(1)
getData()
}
return (
<div className="flex flex-col gap-4 text-black">
<div className="flex flex-col gap-2 rounded-xl bg-white">
<p className="mx-4 text-3xl font-semibold">Spesific Target Mapping</p>
<p className="mx-4 text-sm text-gray-700">
Manage your Spesific Target Mapping
</p>
<div className="m-4 flex flex-row items-end gap-4 rounded-xl border border-violet-200 p-4">
<div className="flex flex-col gap-1">
<p className="text-xs font-light uppercase">Search</p>
<InputGroup className="h-10 w-100 rounded-lg border border-violet-300 bg-transparent text-black outline-none focus:border-transparent focus:ring-0 focus:outline-none">
<InputGroupInput
value={search}
onChange={(e) => setSearch(e.target.value)}
id="inline-end-input"
type="text"
placeholder="Search e.g username, email or ID"
/>
<InputGroupAddon align="inline-start">
<a
className="cursor-pointer"
// onClick={() => setViewPassword(!viewPassword)}
>
<SearchIcon />
</a>
</InputGroupAddon>
</InputGroup>
</div>
<div className="flex flex-col gap-1">
<p className="text-xs font-light uppercase">Proxy Location</p>
<Select
value={selectedLocation}
onValueChange={setSelectedLocation}
>
<SelectTrigger className="h-10! w-70 rounded-lg border border-violet-300 bg-transparent text-black outline-none focus:border-transparent focus:ring-0 focus:outline-none">
<SelectValue placeholder="Select Location" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{dummyProxy.map((proxy) => (
<div key={proxy.id}>
<SelectItem value={String(proxy.id)}>
{proxy.value}
</SelectItem>
</div>
))}
</SelectGroup>
</SelectContent>
</Select>
</div>
<Button
onClick={getData}
className="h-10 w-24 bg-blue-600 text-white"
>
Filter
</Button>
<Button
onClick={resetFilter}
className="bg-grey-50 h-10 w-24 border-2 border-gray-300 text-black"
>
Reset
</Button>
</div>
</div>
<div className="m-4 flex flex-col gap-2 rounded-xl border border-violet-200 bg-white p-4">
<p className="text-lg font-bold text-black">Accounts</p>
<Table className="border border-violet-300">
<TableHeader className="bg-violet-50">
<TableRow className="hover:bg-transparent">
<TableHead className="w-25 text-black"></TableHead>
<TableHead className="text-black">Identifier</TableHead>
<TableHead className="text-black">Proxy Location</TableHead>
<TableHead className="text-black">Action</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{dummyData.map((invoice, index) => (
<TableRow className="hover:bg-gray-200" key={invoice.id}>
<TableCell className="font-medium">{index + 1}</TableCell>
<TableCell>{invoice.identifier}</TableCell>
<TableCell>{invoice.proxy}</TableCell>
<TableCell className="">
<Button
disabled={invoice.sentiment == 2 || invoice.sentiment == 4}
onClick={() => {
console.log("selectData", invoice.id)
}}
className="cursor-pointer bg-blue-900 text-white"
>
<ReloadIcon /> Mapping
</Button>
</TableCell>
</TableRow>
))}
</TableBody>
<TableFooter className="bg-violet-50">
<TableRow className="hover:bg-transparent">
<TableCell colSpan={4} className="">
<div className="flex flex-row items-center justify-end gap-2">
<p className="text-blue-400">ROWS PER PAGE: </p>
<Select value={limit} onValueChange={setLimit}>
<SelectTrigger className="w-20">
<SelectValue placeholder="value" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="5">5</SelectItem>
<SelectItem value="10">10</SelectItem>
<SelectItem value="25">25</SelectItem>
<SelectItem value="50">50</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<a className="cursor-pointer">
<ChevronLeft />
</a>
<a className="cursor-pointer">
<ChevronRight />
</a>
</div>
</TableCell>
</TableRow>
</TableFooter>
</Table>
<div className="my-4 flex justify-between">
<p className="text-lg font-bold text-black">
Spesific Targets Mapping
</p>
<InputGroup className="h-10 w-80 rounded-lg border border-violet-300 bg-transparent text-black outline-none focus:border-transparent focus:ring-0 focus:outline-none">
<InputGroupInput
value={search}
onChange={(e) => setSearch(e.target.value)}
id="inline-end-input"
type="text"
placeholder="Search"
/>
<InputGroupAddon align="inline-start">
<a
className="cursor-pointer"
// onClick={() => setViewPassword(!viewPassword)}
>
<SearchIcon />
</a>
</InputGroupAddon>
</InputGroup>
</div>
<Table className="border border-violet-300">
<TableHeader className="bg-violet-50">
<TableRow className="hover:bg-transparent">
<TableHead className="text-black">NO</TableHead>
<TableHead className="text-black">Name</TableHead>
<TableHead className="text-black">Sentiment</TableHead>
<TableHead className="text-black">Selected</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{dummyDataTarget.map((target, index) => (
<TableRow className="hover:bg-gray-200" key={target.id}>
<TableCell className="font-medium">{index + 1}</TableCell>
<TableCell>{target.name}</TableCell>
<TableCell>
<Select
value={String(target.status)}
onValueChange={setSelectedLocation}
>
<SelectTrigger className="h-10! w-70 rounded-lg border border-violet-300 bg-transparent text-black outline-none focus:border-transparent focus:ring-0 focus:outline-none">
<SelectValue placeholder="Select Location" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{dummyStatus.map((proxy) => (
<div key={proxy.id}>
<SelectItem value={String(proxy.id)}>
{proxy.value}
</SelectItem>
</div>
))}
</SelectGroup>
</SelectContent>
</Select>
</TableCell>
<TableCell className="space-x-2">
<Checkbox
checked={selectedDataTable.includes(target.id)}
onCheckedChange={(e) => {
if (e) {
setSelectedDataTable([...selectedDataTable, target.id])
} else {
const temp = []
for (const element of selectedDataTable) {
if (element !== target.id) {
temp.push(element)
}
}
setSelectedDataTable(temp)
}
}}
className="border-gray-300"
/>
</TableCell>
</TableRow>
))}
</TableBody>
<TableFooter className="bg-violet-50">
<TableRow className="hover:bg-transparent">
<TableCell colSpan={4} className="">
<div className="flex flex-row items-center justify-end gap-2">
<p className="text-blue-400">ROWS PER PAGE: </p>
<Select value={limit} onValueChange={setLimit}>
<SelectTrigger className="w-20">
<SelectValue placeholder="value" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="5">5</SelectItem>
<SelectItem value="10">10</SelectItem>
<SelectItem value="25">25</SelectItem>
<SelectItem value="50">50</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<a className="cursor-pointer">
<ChevronLeft />
</a>
<a className="cursor-pointer">
<ChevronRight />
</a>
</div>
</TableCell>
</TableRow>
</TableFooter>
</Table>
</div>
</div>
)
}

View File

@ -63,7 +63,7 @@ export function AppSidebar() {
<Link
key={item.title}
href={"/dashboard/" + item.title}
className={`flex w-full items-center justify-start gap-3 rounded-lg p-3 text-sm ${pathname.includes(item.title) ? "border-2 border-violet-600 bg-violet-100 font-bold text-violet-600" : "text-gray-600"} transition group-data-[state=collapsed]:justify-center hover:bg-white/10`}
className={`flex w-full items-center justify-start gap-3 rounded-lg p-3 text-sm ${pathname.split("/")[2] == item.title ? "border-2 border-violet-600 bg-violet-100 font-bold text-violet-600" : "text-gray-600"} transition group-data-[state=collapsed]:justify-center hover:bg-white/10`}
>
{item.icon}
<span className="capitalize group-data-[state=collapsed]:hidden">