feat: update campaign detail
This commit is contained in:
parent
968f2642cc
commit
fd021426d1
|
|
@ -127,7 +127,7 @@ const AccountListTable = () => {
|
|||
|
||||
return (
|
||||
<div className="w-full overflow-x-auto bg-white p-4 rounded-sm space-y-3">
|
||||
<div className="flex justify-between mb-10 items-center">
|
||||
<div className="flex justify-between mb-3 items-center">
|
||||
<p className="text-xl font-medium text-default-900">Daftar Akun</p>
|
||||
<div className="flex flex-row gap-3">
|
||||
<Link href="/admin/broadcast/campaign-list/account-list/create">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,387 @@
|
|||
'use client'
|
||||
|
||||
import "react-datepicker/dist/react-datepicker.css";
|
||||
import { Icon } from "@iconify/react";
|
||||
import Link from "next/link";
|
||||
import { useRouter, usePathname } from "next/navigation";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useMediaQuery } from "react-responsive";
|
||||
import { close, loading } from "@/config/swal";
|
||||
import ReactDatePicker from "react-datepicker";
|
||||
import { getOnlyDate } from "@/utils/globals";
|
||||
import AccountListTable from "../../account-list/component/table";
|
||||
import {
|
||||
ColumnDef,
|
||||
ColumnFiltersState,
|
||||
PaginationState,
|
||||
SortingState,
|
||||
VisibilityState,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
getFilteredRowModel,
|
||||
getPaginationRowModel,
|
||||
getSortedRowModel,
|
||||
useReactTable,
|
||||
} from "@tanstack/react-table";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import TablePagination from "@/components/table/table-pagination";
|
||||
import {
|
||||
getMediaBlastCampaignById,
|
||||
getMediaBlastBroadcastList
|
||||
} from "@/service/broadcast/broadcast";
|
||||
|
||||
// Types
|
||||
interface CampaignData {
|
||||
id: string;
|
||||
no: number;
|
||||
mediaBlastCampaignId: string;
|
||||
mediaBlastCampaign: {
|
||||
title: string;
|
||||
};
|
||||
subject: string;
|
||||
type: string;
|
||||
status: string;
|
||||
sendDate: string;
|
||||
}
|
||||
|
||||
interface PaginatedResponse {
|
||||
content: CampaignData[];
|
||||
totalPages: number;
|
||||
totalElements: number;
|
||||
}
|
||||
|
||||
interface PageProps {
|
||||
params: {
|
||||
id: string;
|
||||
locale: string;
|
||||
};
|
||||
searchParams: {
|
||||
page?: string;
|
||||
size?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export default function BroadcastCampaignDetail({ params, searchParams }: PageProps) {
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const { id, locale } = params;
|
||||
const [getData, setGetData] = useState<CampaignData[]>([]);
|
||||
const [totalPage, setTotalPage] = useState<number>(0);
|
||||
const [totalData, setTotalData] = useState<number>(0);
|
||||
const [activeTab, setActiveTab] = useState<"sent" | "schedule" | "account-list">("sent");
|
||||
const { page, size } = searchParams;
|
||||
|
||||
const [calenderState, setCalenderState] = useState<boolean>(false);
|
||||
const [typeFilter, setTypeFilter] = useState<string>("email");
|
||||
const [dateRange, setDateRange] = useState<[Date, Date]>([new Date(), new Date()]);
|
||||
const [startDate, endDate] = dateRange;
|
||||
|
||||
const [startDateString, setStartDateString] = useState<string | undefined>();
|
||||
const [endDateString, setEndDateString] = useState<string | undefined>();
|
||||
|
||||
// Table state
|
||||
const [sorting, setSorting] = useState<SortingState>([]);
|
||||
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
|
||||
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({});
|
||||
const [rowSelection, setRowSelection] = useState({});
|
||||
const [pagination, setPagination] = useState<PaginationState>({
|
||||
pageIndex: 0,
|
||||
pageSize: parseInt(size || "10"),
|
||||
});
|
||||
|
||||
const pages = page ? parseInt(page) - 1 : 0;
|
||||
const currentPage = page ? parseInt(page) : 1;
|
||||
const pageSize = parseInt(size || "10");
|
||||
|
||||
const isFHD = useMediaQuery({
|
||||
minWidth: 1920,
|
||||
});
|
||||
|
||||
const setCurrentPage = (pageNumber: number) => {
|
||||
const params = new URLSearchParams(searchParams);
|
||||
params.set('page', pageNumber.toString());
|
||||
router.push(`${pathname}?${params.toString()}`);
|
||||
};
|
||||
|
||||
async function getListPaginationData() {
|
||||
loading();
|
||||
console.log("Type : ", typeFilter);
|
||||
console.log("Date : ", startDateString, endDateString);
|
||||
|
||||
try {
|
||||
const res = await getMediaBlastBroadcastList(
|
||||
pages,
|
||||
activeTab === "schedule",
|
||||
startDateString || "",
|
||||
endDateString || "",
|
||||
typeFilter,
|
||||
id
|
||||
);
|
||||
|
||||
close();
|
||||
if (res?.data?.data) {
|
||||
setupData(res.data.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getListPaginationData();
|
||||
}, [currentPage, pageSize, activeTab, endDateString, startDateString, typeFilter]);
|
||||
|
||||
function setupData(rawData: PaginatedResponse) {
|
||||
console.log("raw", rawData);
|
||||
if (rawData !== undefined) {
|
||||
const dataContent = rawData?.content;
|
||||
const data: CampaignData[] = [];
|
||||
|
||||
dataContent.forEach((element, i) => {
|
||||
element.no = (currentPage - 1) * pageSize + i + 1;
|
||||
data.push(element);
|
||||
});
|
||||
|
||||
setGetData(data);
|
||||
setTotalPage(rawData?.totalPages);
|
||||
setTotalData(rawData?.totalElements);
|
||||
}
|
||||
}
|
||||
|
||||
const columns: ColumnDef<CampaignData>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => <span>{row.getValue("no")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "mediaBlastCampaign.title",
|
||||
header: "Campaign",
|
||||
cell: ({ row }) => (
|
||||
<Link href={`/${locale}/admin/broadcast/campaign-list/detail/${row.original.mediaBlastCampaignId}`} className="text-dark">
|
||||
<span className="font-weight-bold">{row.original.mediaBlastCampaign?.title}</span>
|
||||
</Link>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "subject",
|
||||
header: "Judul",
|
||||
cell: ({ row }) => (
|
||||
<Link href={`/${locale}/admin/broadcast/content/detail/${row.original.id}`} className="text-dark">
|
||||
<span className="font-weight-bold">{row.getValue("subject")}</span>
|
||||
</Link>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "type",
|
||||
header: "Tipe",
|
||||
cell: ({ row }) => (
|
||||
<div className="text-right text-black">
|
||||
{row.getValue("type")}
|
||||
</div>
|
||||
)
|
||||
},
|
||||
{
|
||||
accessorKey: "status",
|
||||
header: "Status",
|
||||
cell: ({ row }) => (
|
||||
<div className="text-right text-black">
|
||||
{row.getValue("status")}
|
||||
</div>
|
||||
)
|
||||
},
|
||||
{
|
||||
accessorKey: "sendDate",
|
||||
header: "Tanggal & Waktu",
|
||||
cell: ({ row }) => (
|
||||
<div className="text-black">
|
||||
{row.getValue("sendDate")}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
const table = useReactTable({
|
||||
data: getData,
|
||||
columns,
|
||||
onSortingChange: setSorting,
|
||||
onColumnFiltersChange: setColumnFilters,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getPaginationRowModel: getPaginationRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
getFilteredRowModel: getFilteredRowModel(),
|
||||
onColumnVisibilityChange: setColumnVisibility,
|
||||
onRowSelectionChange: setRowSelection,
|
||||
onPaginationChange: setPagination,
|
||||
state: {
|
||||
sorting,
|
||||
columnFilters,
|
||||
columnVisibility,
|
||||
rowSelection,
|
||||
pagination,
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
function initState() {
|
||||
if (startDate != null && endDate != null) {
|
||||
setStartDateString(getOnlyDate(startDate));
|
||||
setEndDateString(getOnlyDate(endDate));
|
||||
}
|
||||
}
|
||||
console.log('date range', dateRange);
|
||||
initState();
|
||||
}, [calenderState, startDate, endDate]);
|
||||
|
||||
const handleTypeFilter = (type: string) => {
|
||||
setTypeFilter(type);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-white container-fluid rounded rounded-xl">
|
||||
<div className="mt-1 p-4">
|
||||
<div className="flex flex-row gap-1 border-2 rounded-md w-fit mb-4">
|
||||
<Button
|
||||
onClick={() => setActiveTab("sent")}
|
||||
size="md"
|
||||
className={`hover:text-white ${
|
||||
activeTab === "sent"
|
||||
? "bg-indigo-600 text-white "
|
||||
: "bg-white text-black "
|
||||
}`}
|
||||
>
|
||||
Sent
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => setActiveTab("schedule")}
|
||||
size="md"
|
||||
className={`hover:text-white ${
|
||||
activeTab === "schedule"
|
||||
? "bg-indigo-600 text-white "
|
||||
: "bg-white text-black "
|
||||
}`}
|
||||
>
|
||||
Schedule
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => setActiveTab("account-list")}
|
||||
size="md"
|
||||
className={`hover:text-white ${
|
||||
activeTab === "account-list"
|
||||
? "bg-indigo-600 text-white "
|
||||
: "bg-white text-black "
|
||||
}`}
|
||||
>
|
||||
List Akun
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{activeTab === "account-list" ? (
|
||||
<AccountListTable />
|
||||
) : (
|
||||
<>
|
||||
<div className="broadcast-filter flex flex-column gap-3 mb-4">
|
||||
<div className="flex flex-row gap-1 border-2 rounded-md w-fit h-fit">
|
||||
<Button
|
||||
onClick={() => handleTypeFilter("email")}
|
||||
className={`hover:text-white ${
|
||||
typeFilter === "email"
|
||||
? "bg-black text-white "
|
||||
: "bg-white text-black "
|
||||
}`}
|
||||
size='sm'
|
||||
>
|
||||
Email Blast
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => handleTypeFilter("wa")}
|
||||
className={`hover:text-white ${
|
||||
typeFilter === "wa"
|
||||
? "bg-black text-white "
|
||||
: "bg-white text-black "
|
||||
}`}
|
||||
size='sm'
|
||||
>
|
||||
WhatsApp Blast
|
||||
</Button>
|
||||
</div>
|
||||
<div className="dashboard-date-picker">
|
||||
<div className="mx-6 my-1">
|
||||
<ReactDatePicker
|
||||
selectsRange
|
||||
startDate={startDate}
|
||||
endDate={endDate}
|
||||
onChange={(update) => {
|
||||
setDateRange(update as [Date, Date]);
|
||||
}}
|
||||
placeholderText="Pilih Tanggal"
|
||||
onCalendarClose={() => setCalenderState(!calenderState)}
|
||||
className="form-control rounded-pill"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="w-full overflow-x-auto">
|
||||
<Table className="overflow-hidden mt-3">
|
||||
<TableHeader>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<TableRow key={headerGroup.id} className="bg-default-200">
|
||||
{headerGroup.headers.map((header) => (
|
||||
<TableHead key={header.id}>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
: flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext()
|
||||
)}
|
||||
</TableHead>
|
||||
))}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{table.getRowModel().rows?.length ? (
|
||||
table.getRowModel().rows.map((row) => (
|
||||
<TableRow
|
||||
key={row.id}
|
||||
data-state={row.getIsSelected() && "selected"}
|
||||
className="h-[75px]"
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell key={cell.id}>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={columns.length} className="h-24 text-center">
|
||||
No results.
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<TablePagination
|
||||
table={table}
|
||||
totalData={totalData}
|
||||
totalPage={totalPage}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -17,32 +17,6 @@ export default function AdminBroadcast() {
|
|||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="w-full overflow-x-auto bg-white p-4 rounded-sm space-y-3">
|
||||
<div className="flex flex-row gap-1 border-2 rounded-md w-fit mb-5">
|
||||
<Button
|
||||
rounded="md"
|
||||
onClick={() => setTab("Email Blast")}
|
||||
className={` hover:text-white
|
||||
${
|
||||
tab === "Email Blast"
|
||||
? "bg-black text-white "
|
||||
: "bg-white text-black "
|
||||
}`}
|
||||
>
|
||||
Email Blast
|
||||
</Button>
|
||||
<Button
|
||||
rounded="md"
|
||||
onClick={() => setTab("WhatsApp Blast")}
|
||||
className={` hover:text-white
|
||||
${
|
||||
tab === "WhatsApp Blast"
|
||||
? "bg-black text-white "
|
||||
: "bg-white text-black "
|
||||
}`}
|
||||
>
|
||||
WhatsApp Blast
|
||||
</Button>
|
||||
</div>
|
||||
{tab === "Email Blast" && <BroadcastEmailTable />}
|
||||
{tab === "WhatsApp Blast" && <BroadcastWhatsAppTable />}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -100,6 +100,18 @@ export async function saveMediaBlastBroadcast(data: any) {
|
|||
return httpPostInterceptor(url, data);
|
||||
}
|
||||
|
||||
export async function getMediaBlastBroadcastList(
|
||||
page: number,
|
||||
isScheduled: boolean,
|
||||
startDate: string,
|
||||
endDate: string,
|
||||
type: string,
|
||||
campaignId: string
|
||||
) {
|
||||
const url = `media/blast/broadcast/list?enablePage=1&page=${page}&isScheduled=${isScheduled}&type=${type}&startDate=${startDate}&endDate=${endDate}&campaignId=${campaignId}`;
|
||||
return httpGetInterceptor(url);
|
||||
}
|
||||
|
||||
export async function listDataPopUp(
|
||||
page: number,
|
||||
limit: string,
|
||||
|
|
|
|||
Loading…
Reference in New Issue