feat: update media broadcast, update blogs
This commit is contained in:
parent
902f8de516
commit
3fee36390d
|
|
@ -30,34 +30,27 @@ const columns: ColumnDef<any>[] = [
|
||||||
accessorKey: "accountName",
|
accessorKey: "accountName",
|
||||||
header: "Nama",
|
header: "Nama",
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<span className="normal-case">{row.original.mediaBlastAccount.accountName}</span>
|
<span className="normal-case">{row.original.mediaBlastAccountName}</span>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: "accountType",
|
accessorKey: "accountType",
|
||||||
header: "Tipe Akun",
|
header: "Tipe Akun",
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<span className="normal-case">{row.original.mediaBlastAccount.accountType}</span>
|
<span className="normal-case">{row.original.mediaBlastAccountType}</span>
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessorKey: "accountCategory",
|
|
||||||
header: "Kategory",
|
|
||||||
cell: ({ row }) => (
|
|
||||||
<span className="uppercase">{row.original.mediaBlastAccount.accountCategory}</span>
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: "emailAddress",
|
accessorKey: "emailAddress",
|
||||||
header: "Email",
|
header: "Email",
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<span className="normal-case">{row.original.mediaBlastAccount.emailAddress}</span>
|
<span className="normal-case">{row.original.mediaBlastAccountEmail}</span>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: "whatsappNumber",
|
accessorKey: "whatsappNumber",
|
||||||
header: "Whatsapp",
|
header: "Whatsapp",
|
||||||
cell: ({ row }) => <span>{row.original.mediaBlastAccount.whatsappNumber}</span>,
|
cell: ({ row }) => <span>{row.original.mediaBlastAccountPhone}</span>,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "actions",
|
id: "actions",
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ import {
|
||||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import {
|
import {
|
||||||
Select,
|
Select as UISelect,
|
||||||
SelectContent,
|
SelectContent,
|
||||||
SelectItem,
|
SelectItem,
|
||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
|
|
@ -50,15 +50,17 @@ import { Icon } from "@iconify/react";
|
||||||
import { useParams, useSearchParams } from "next/navigation";
|
import { useParams, useSearchParams } from "next/navigation";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { X } from "lucide-react";
|
import { X } from "lucide-react";
|
||||||
|
import ReactSelect from "react-select";
|
||||||
|
|
||||||
import columns from "./column";
|
import columns from "./column";
|
||||||
import TablePagination from "@/components/table/table-pagination";
|
import TablePagination from "@/components/table/table-pagination";
|
||||||
import {
|
import {
|
||||||
getMediaBlastCampaignAccountList,
|
getMediaBlastCampaignAccountList,
|
||||||
deleteMediaBlastCampaignAccount,
|
deleteMediaBlastCampaignAccount,
|
||||||
saveMediaBlastCampaignAccount,
|
saveMediaBlastCampaignAccountBulk,
|
||||||
} from "@/service/broadcast/broadcast";
|
} from "@/service/broadcast/broadcast";
|
||||||
import { close, loading, error, success } from "@/config/swal";
|
import { AdministrationUserList } from "@/service/management-user/management-user";
|
||||||
|
import { close, loading, error, success, successCallback } from "@/config/swal";
|
||||||
|
|
||||||
// Mock data for available accounts - replace with actual API call
|
// Mock data for available accounts - replace with actual API call
|
||||||
const availableAccounts = [
|
const availableAccounts = [
|
||||||
|
|
@ -97,6 +99,7 @@ const AccountListTable = () => {
|
||||||
const [selectedAccount, setSelectedAccount] = React.useState<any[]>([]);
|
const [selectedAccount, setSelectedAccount] = React.useState<any[]>([]);
|
||||||
const [selectedCategory, setSelectedCategory] = React.useState<string>("");
|
const [selectedCategory, setSelectedCategory] = React.useState<string>("");
|
||||||
const [availableAccountsList, setAvailableAccountsList] = React.useState<any[]>(availableAccounts);
|
const [availableAccountsList, setAvailableAccountsList] = React.useState<any[]>(availableAccounts);
|
||||||
|
const [usersList, setUsersList] = React.useState<any[]>([]);
|
||||||
|
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
|
|
@ -170,53 +173,60 @@ const AccountListTable = () => {
|
||||||
loading();
|
loading();
|
||||||
|
|
||||||
if (accountCategory === "all-account") {
|
if (accountCategory === "all-account") {
|
||||||
// Handle all accounts selection
|
// Handle all accounts - send only campaignId and category "all"
|
||||||
const allAccounts = availableAccountsList.map(acc => ({
|
const request = {
|
||||||
mediaBlastCampaignId: campaignId,
|
mediaBlastCampaignId: campaignId,
|
||||||
mediaBlastAccountId: acc.id,
|
mediaBlastAccountCategory: "all",
|
||||||
}));
|
};
|
||||||
|
const response = await saveMediaBlastCampaignAccountBulk(request);
|
||||||
for (const request of allAccounts) {
|
if (response?.error) {
|
||||||
const response = await saveMediaBlastCampaignAccount(request);
|
error(response.message);
|
||||||
if (response?.error) {
|
return;
|
||||||
error(response.message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (accountCategory === "kategori" && selectedCategory) {
|
} else if (accountCategory === "kategori" && selectedCategory) {
|
||||||
// Handle category selection
|
// Handle category selection - send campaignId and role-based category
|
||||||
const categoryAccounts = availableAccountsList.filter(
|
let roleId = "";
|
||||||
acc => acc.category === selectedCategory
|
switch (selectedCategory) {
|
||||||
);
|
case "umum":
|
||||||
|
roleId = "5";
|
||||||
|
break;
|
||||||
|
case "jurnalis":
|
||||||
|
roleId = "6";
|
||||||
|
break;
|
||||||
|
case "polri":
|
||||||
|
roleId = "7";
|
||||||
|
break;
|
||||||
|
case "ksp":
|
||||||
|
roleId = "8";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
roleId = "5";
|
||||||
|
}
|
||||||
|
|
||||||
for (const acc of categoryAccounts) {
|
const request = {
|
||||||
const request = {
|
mediaBlastCampaignId: campaignId,
|
||||||
mediaBlastCampaignId: campaignId,
|
mediaBlastAccountCategory: `role-${roleId}`,
|
||||||
mediaBlastAccountId: acc.id,
|
};
|
||||||
};
|
const response = await saveMediaBlastCampaignAccountBulk(request);
|
||||||
const response = await saveMediaBlastCampaignAccount(request);
|
if (response?.error) {
|
||||||
if (response?.error) {
|
error(response.message);
|
||||||
error(response.message);
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (accountCategory === "custom") {
|
} else if (accountCategory === "custom") {
|
||||||
// Handle custom selection
|
// Handle custom selection - send campaignId and selected user IDs
|
||||||
for (const acc of selectedAccount) {
|
const request = {
|
||||||
const request = {
|
mediaBlastCampaignId: campaignId,
|
||||||
mediaBlastCampaignId: campaignId,
|
mediaBlastAccountIds: selectedAccount.map(acc => acc.id),
|
||||||
mediaBlastAccountId: acc.id,
|
};
|
||||||
};
|
const response = await saveMediaBlastCampaignAccountBulk(request);
|
||||||
const response = await saveMediaBlastCampaignAccount(request);
|
if (response?.error) {
|
||||||
if (response?.error) {
|
error(response.message);
|
||||||
error(response.message);
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
close();
|
close();
|
||||||
success("Akun berhasil ditambahkan ke campaign!");
|
successCallback("Akun berhasil ditambahkan ke campaign!");
|
||||||
resetDialogState();
|
resetDialogState();
|
||||||
fetchData();
|
fetchData();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
@ -229,9 +239,32 @@ const AccountListTable = () => {
|
||||||
setAccountCategory("");
|
setAccountCategory("");
|
||||||
setSelectedAccount([]);
|
setSelectedAccount([]);
|
||||||
setSelectedCategory("");
|
setSelectedCategory("");
|
||||||
|
setUsersList([]);
|
||||||
setIsDialogOpen(false);
|
setIsDialogOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const fetchUsersList = async () => {
|
||||||
|
try {
|
||||||
|
loading();
|
||||||
|
const response = await AdministrationUserList(
|
||||||
|
"1", // levelId
|
||||||
|
0, // page
|
||||||
|
"", // name
|
||||||
|
"100", // size
|
||||||
|
"1", // featureId
|
||||||
|
"" // role
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response?.data?.data?.content) {
|
||||||
|
setUsersList(response.data.data.content);
|
||||||
|
}
|
||||||
|
close();
|
||||||
|
} catch (err) {
|
||||||
|
close();
|
||||||
|
error("Terjadi kesalahan saat mengambil daftar user");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleFilter = (id: string, checked: boolean) => {
|
const handleFilter = (id: string, checked: boolean) => {
|
||||||
let temp = [...filtered];
|
let temp = [...filtered];
|
||||||
if (checked) temp = [...temp, id];
|
if (checked) temp = [...temp, id];
|
||||||
|
|
@ -239,16 +272,7 @@ const AccountListTable = () => {
|
||||||
setFiltered(temp);
|
setFiltered(temp);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAccountSelection = (accountId: string, checked: boolean) => {
|
|
||||||
if (checked) {
|
|
||||||
const account = availableAccountsList.find(acc => acc.id === accountId);
|
|
||||||
if (account && !selectedAccount.find(acc => acc.id === accountId)) {
|
|
||||||
setSelectedAccount([...selectedAccount, account]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setSelectedAccount(selectedAccount.filter(acc => acc.id !== accountId));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const removeSelectedAccount = (accountId: string) => {
|
const removeSelectedAccount = (accountId: string) => {
|
||||||
setSelectedAccount(selectedAccount.filter(acc => acc.id !== accountId));
|
setSelectedAccount(selectedAccount.filter(acc => acc.id !== accountId));
|
||||||
|
|
@ -274,20 +298,23 @@ const AccountListTable = () => {
|
||||||
Pilih Akun
|
Pilih Akun
|
||||||
</Button>
|
</Button>
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
<DialogContent className="max-w-2xl max-h-[80vh] overflow-y-auto">
|
<DialogContent size="md" className="max-w-xl max-h-[80vh] overflow-y-auto">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>Pilih Akun Untuk Campaign Ini</DialogTitle>
|
<DialogTitle>Pilih Akun Untuk Campaign Ini</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
<div className="space-y-4">
|
<div className="space-y-4 my-3">
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
value={accountCategory}
|
value={accountCategory}
|
||||||
onValueChange={(val) => {
|
onValueChange={(val) => {
|
||||||
setAccountCategory(val);
|
setAccountCategory(val);
|
||||||
setSelectedAccount([]);
|
setSelectedAccount([]);
|
||||||
setSelectedCategory("");
|
setSelectedCategory("");
|
||||||
|
if (val === "custom") {
|
||||||
|
fetchUsersList();
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
className="space-y-3"
|
className="flex space-x-6"
|
||||||
>
|
>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<RadioGroupItem value="all-account" id="all-account" />
|
<RadioGroupItem value="all-account" id="all-account" />
|
||||||
|
|
@ -299,7 +326,7 @@ const AccountListTable = () => {
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<RadioGroupItem value="custom" id="custom" />
|
<RadioGroupItem value="custom" id="custom" />
|
||||||
<Label htmlFor="custom">Custom</Label>
|
<Label htmlFor="custom">Kustom</Label>
|
||||||
</div>
|
</div>
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
|
|
||||||
|
|
@ -307,7 +334,7 @@ const AccountListTable = () => {
|
||||||
{accountCategory === "kategori" && (
|
{accountCategory === "kategori" && (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label>Pilih Kategori:</Label>
|
<Label>Pilih Kategori:</Label>
|
||||||
<Select onValueChange={(val) => setSelectedCategory(val)}>
|
<UISelect onValueChange={(val) => setSelectedCategory(val)}>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder="Pilih kategori" />
|
<SelectValue placeholder="Pilih kategori" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
|
|
@ -317,37 +344,47 @@ const AccountListTable = () => {
|
||||||
<SelectItem value="ksp">KSP</SelectItem>
|
<SelectItem value="ksp">KSP</SelectItem>
|
||||||
<SelectItem value="jurnalis">Jurnalis</SelectItem>
|
<SelectItem value="jurnalis">Jurnalis</SelectItem>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</UISelect>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Custom Account Selection */}
|
{/* Custom Account Selection */}
|
||||||
{accountCategory === "custom" && (
|
{accountCategory === "custom" && (
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<Label>Pilih Akun:</Label>
|
<Label>Pilih User:</Label>
|
||||||
<div className="grid grid-cols-1 gap-2 max-h-60 overflow-y-auto">
|
<ReactSelect
|
||||||
{getFilteredAccounts().map((acc) => (
|
isMulti
|
||||||
<div key={acc.id} className="flex items-center space-x-2">
|
options={usersList.map((user: any) => ({
|
||||||
<Checkbox
|
value: user.id,
|
||||||
id={`acc-${acc.id}`}
|
label: `${user.fullname} (${user.role?.name})`,
|
||||||
checked={selectedAccount.some(selected => selected.id === acc.id)}
|
user: user
|
||||||
onCheckedChange={(checked) => handleAccountSelection(acc.id, Boolean(checked))}
|
}))}
|
||||||
/>
|
value={selectedAccount.map((acc: any) => ({
|
||||||
<Label htmlFor={`acc-${acc.id}`} className="text-sm">
|
value: acc.id,
|
||||||
{acc.accountName} ({acc.category.toUpperCase()})
|
label: `${acc.fullname} (${acc.role?.name})`,
|
||||||
</Label>
|
user: acc
|
||||||
</div>
|
}))}
|
||||||
))}
|
onChange={(selectedOptions: any) => {
|
||||||
</div>
|
const selectedUsers = selectedOptions ? selectedOptions.map((option: any) => option.user) : [];
|
||||||
|
setSelectedAccount(selectedUsers);
|
||||||
|
}}
|
||||||
|
placeholder="Cari dan pilih user..."
|
||||||
|
noOptionsMessage={() => "Tidak ada user ditemukan"}
|
||||||
|
loadingMessage={() => "Memuat..."}
|
||||||
|
isSearchable={true}
|
||||||
|
isClearable={true}
|
||||||
|
className="react-select"
|
||||||
|
classNamePrefix="select"
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Selected Accounts Display */}
|
{/* Selected Accounts Display */}
|
||||||
{selectedAccount.length > 0 && (
|
{selectedAccount.length > 0 && (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label>Akun Terpilih:</Label>
|
<Label>User Terpilih ({selectedAccount.length}):</Label>
|
||||||
<div className="flex flex-wrap gap-2">
|
<div className="flex flex-wrap gap-2">
|
||||||
{selectedAccount.map((acc) => (
|
{selectedAccount.map((acc) => (
|
||||||
<Badge key={acc.id} variant="secondary" className="flex items-center gap-1">
|
<Badge key={acc.id} className="flex items-center gap-1">
|
||||||
{acc.accountName}
|
{acc.fullname}
|
||||||
<X
|
<X
|
||||||
className="h-3 w-3 cursor-pointer"
|
className="h-3 w-3 cursor-pointer"
|
||||||
onClick={() => removeSelectedAccount(acc.id)}
|
onClick={() => removeSelectedAccount(acc.id)}
|
||||||
|
|
@ -364,7 +401,7 @@ const AccountListTable = () => {
|
||||||
{accountCategory === "all-account" && (
|
{accountCategory === "all-account" && (
|
||||||
<div className="p-3 bg-blue-50 rounded-md">
|
<div className="p-3 bg-blue-50 rounded-md">
|
||||||
<p className="text-sm text-blue-700">
|
<p className="text-sm text-blue-700">
|
||||||
Semua akun ({availableAccountsList.length} akun) akan ditambahkan ke campaign ini.
|
Semua akun akan ditambahkan ke campaign ini.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
@ -373,7 +410,16 @@ const AccountListTable = () => {
|
||||||
{accountCategory === "kategori" && selectedCategory && (
|
{accountCategory === "kategori" && selectedCategory && (
|
||||||
<div className="p-3 bg-green-50 rounded-md">
|
<div className="p-3 bg-green-50 rounded-md">
|
||||||
<p className="text-sm text-green-700">
|
<p className="text-sm text-green-700">
|
||||||
{getFilteredAccounts().length} akun dari kategori "{selectedCategory}" akan ditambahkan.
|
Semua akun dengan role "{selectedCategory.toUpperCase()}" akan ditambahkan.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Custom Selection Info */}
|
||||||
|
{accountCategory === "custom" && (
|
||||||
|
<div className="p-3 bg-purple-50 rounded-md">
|
||||||
|
<p className="text-sm text-purple-700">
|
||||||
|
{selectedAccount.length} user terpilih akan ditambahkan ke campaign ini.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ import { postBlog, uploadThumbnailBlog } from "@/service/blog/blog";
|
||||||
import dynamic from "next/dynamic";
|
import dynamic from "next/dynamic";
|
||||||
import { error } from "console";
|
import { error } from "console";
|
||||||
import { loading } from "@/lib/swal";
|
import { loading } from "@/lib/swal";
|
||||||
|
import { getCookiesDecrypt } from "@/lib/utils";
|
||||||
|
|
||||||
const taskSchema = z.object({
|
const taskSchema = z.object({
|
||||||
title: z.string().min(1, { message: "Judul diperlukan" }),
|
title: z.string().min(1, { message: "Judul diperlukan" }),
|
||||||
|
|
@ -92,6 +93,7 @@ export default function FormBlog() {
|
||||||
const [thumbnail, setThumbnail] = useState<File | null>(null);
|
const [thumbnail, setThumbnail] = useState<File | null>(null);
|
||||||
const [preview, setPreview] = useState<string | null>(null);
|
const [preview, setPreview] = useState<string | null>(null);
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
|
const roleName = getCookiesDecrypt("urne");
|
||||||
|
|
||||||
const [unitSelection, setUnitSelection] = useState({
|
const [unitSelection, setUnitSelection] = useState({
|
||||||
allUnit: false,
|
allUnit: false,
|
||||||
|
|
@ -180,6 +182,7 @@ export default function FormBlog() {
|
||||||
|
|
||||||
const save = async (data: TaskSchema) => {
|
const save = async (data: TaskSchema) => {
|
||||||
loading();
|
loading();
|
||||||
|
console.log("roleName", roleName);
|
||||||
const finalTags = tags.join(", ");
|
const finalTags = tags.join(", ");
|
||||||
const requestData = {
|
const requestData = {
|
||||||
...data,
|
...data,
|
||||||
|
|
@ -190,6 +193,7 @@ export default function FormBlog() {
|
||||||
metadata: data.meta,
|
metadata: data.meta,
|
||||||
tags: finalTags,
|
tags: finalTags,
|
||||||
isDraft,
|
isDraft,
|
||||||
|
isInternational: roleName?.includes("INT") ? true : false,
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await postBlog(requestData);
|
const response = await postBlog(requestData);
|
||||||
|
|
|
||||||
|
|
@ -63,8 +63,8 @@ export async function saveMediaBlastCampaign(data: {
|
||||||
return httpPostInterceptor(url, data);
|
return httpPostInterceptor(url, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function saveMediaBlastCampaignAccount(data: any) {
|
export async function saveMediaBlastCampaignAccountBulk(data: any) {
|
||||||
const url = `media/blast/campaign-account`;
|
const url = `media/blast/campaign-account-bulk`;
|
||||||
return httpPostInterceptor( url, data );
|
return httpPostInterceptor( url, data );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -111,7 +111,7 @@ export async function getMediaBlastAccount(id: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteMediaBlastAccount(id: string) {
|
export async function deleteMediaBlastAccount(id: string) {
|
||||||
const url = `media/blast/account?id=${id}`;
|
const url = `media/blast/campaign-account?id=${id}`;
|
||||||
return httpDeleteInterceptor(url);
|
return httpDeleteInterceptor(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue