fix: adjust broadcast admin
This commit is contained in:
parent
e5541c3b35
commit
e60b452780
|
|
@ -30,34 +30,34 @@ const columns: ColumnDef<any>[] = [
|
|||
accessorKey: "accountName",
|
||||
header: "Nama",
|
||||
cell: ({ row }) => (
|
||||
<span className="normal-case">{row.getValue("accountName")}</span>
|
||||
<span className="normal-case">{row.original.mediaBlastAccount.accountName}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "accountType",
|
||||
header: "Tipe Akun",
|
||||
cell: ({ row }) => (
|
||||
<span className="normal-case">{row.getValue("accountType")}</span>
|
||||
<span className="normal-case">{row.original.mediaBlastAccount.accountType}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "accountCategory",
|
||||
header: "Kategory",
|
||||
cell: ({ row }) => (
|
||||
<span className="uppercase">{row.getValue("accountCategory")}</span>
|
||||
<span className="uppercase">{row.original.mediaBlastAccount.accountCategory}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "emailAddress",
|
||||
header: "Email",
|
||||
cell: ({ row }) => (
|
||||
<span className="normal-case">{row.getValue("emailAddress")}</span>
|
||||
<span className="normal-case">{row.original.mediaBlastAccount.emailAddress}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "whatsappNumber",
|
||||
header: "Whatsapp",
|
||||
cell: ({ row }) => <span>{row.getValue("whatsappNumber")}</span>,
|
||||
cell: ({ row }) => <span>{row.original.mediaBlastAccount.whatsappNumber}</span>,
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
import * as React from "react";
|
||||
import {
|
||||
ColumnDef,
|
||||
ColumnFiltersState,
|
||||
PaginationState,
|
||||
SortingState,
|
||||
|
|
@ -15,7 +14,6 @@ import {
|
|||
useReactTable,
|
||||
} from "@tanstack/react-table";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
|
|
@ -24,25 +22,48 @@ import {
|
|||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
import { UserIcon } from "lucide-react";
|
||||
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import TablePagination from "@/components/table/table-pagination";
|
||||
import columns from "./column";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
DialogClose,
|
||||
} from "@/components/ui/dialog";
|
||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { getMediaBlastAccountPage } from "@/service/broadcast/broadcast";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { close, loading } from "@/config/swal";
|
||||
import { Link } from "@/i18n/routing";
|
||||
import { Icon } from "@iconify/react/dist/iconify.js";
|
||||
import { Icon } from "@iconify/react";
|
||||
import { useParams, useSearchParams } from "next/navigation";
|
||||
import { UserIcon } from "lucide-react";
|
||||
|
||||
import columns from "./column";
|
||||
import TablePagination from "@/components/table/table-pagination";
|
||||
import {
|
||||
getMediaBlastCampaignAccountList,
|
||||
deleteMediaBlastCampaignAccount,
|
||||
saveMediaBlastCampaignAccount,
|
||||
} from "@/service/broadcast/broadcast";
|
||||
import { close, loading, error } from "@/config/swal";
|
||||
|
||||
const AccountListTable = () => {
|
||||
const router = useRouter();
|
||||
const params = useParams();
|
||||
const searchParams = useSearchParams();
|
||||
const campaignId = params?.id as string;
|
||||
|
||||
const [dataTable, setDataTable] = React.useState<any[]>([]);
|
||||
const [totalData, setTotalData] = React.useState<number>(1);
|
||||
const [sorting, setSorting] = React.useState<SortingState>([]);
|
||||
|
|
@ -56,10 +77,15 @@ const AccountListTable = () => {
|
|||
pageIndex: 0,
|
||||
pageSize: 10,
|
||||
});
|
||||
|
||||
const [page, setPage] = React.useState(1);
|
||||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
const [filtered, setFiltered] = React.useState<string[]>([]);
|
||||
|
||||
// --- state utk Dialog Pilih Akun ---
|
||||
const [accountCategory, setAccountCategory] = React.useState<string>("");
|
||||
const [selectedAccount, setSelectedAccount] = React.useState<any[]>([]);
|
||||
const [selectedCategory, setSelectedCategory] = React.useState<string>("");
|
||||
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
columns,
|
||||
|
|
@ -83,24 +109,24 @@ const AccountListTable = () => {
|
|||
|
||||
React.useEffect(() => {
|
||||
const pageFromUrl = searchParams?.get("page");
|
||||
if (pageFromUrl) {
|
||||
setPage(Number(pageFromUrl));
|
||||
}
|
||||
if (pageFromUrl) setPage(Number(pageFromUrl));
|
||||
}, [searchParams]);
|
||||
|
||||
React.useEffect(() => {
|
||||
fetchData();
|
||||
}, [page]);
|
||||
}, [page, filtered]);
|
||||
|
||||
async function fetchData() {
|
||||
try {
|
||||
loading();
|
||||
const res = await getMediaBlastAccountPage(
|
||||
const res = await getMediaBlastCampaignAccountList(
|
||||
page - 1,
|
||||
filtered ? filtered.join(",") : ""
|
||||
filtered ? filtered.join(",") : "",
|
||||
campaignId
|
||||
);
|
||||
|
||||
const data = res?.data?.data;
|
||||
const contentData = data?.content;
|
||||
const contentData = data?.content || [];
|
||||
contentData.forEach((item: any, index: number) => {
|
||||
item.no = (page - 1) * 10 + index + 1;
|
||||
});
|
||||
|
|
@ -109,20 +135,43 @@ const AccountListTable = () => {
|
|||
setTotalData(data?.totalElements);
|
||||
setTotalPage(data?.totalPages);
|
||||
close();
|
||||
} catch (error) {
|
||||
console.error("Error fetching tasks:", error);
|
||||
} catch (err) {
|
||||
console.error("Error fetching tasks:", err);
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
// --- API helpers ---
|
||||
async function doDeleteAccount(id: string) {
|
||||
loading();
|
||||
const response = await deleteMediaBlastCampaignAccount(id);
|
||||
close();
|
||||
if (response?.error) {
|
||||
error(response.message);
|
||||
return;
|
||||
}
|
||||
fetchData();
|
||||
}
|
||||
|
||||
async function saveCampaignAccount() {
|
||||
for (const acc of selectedAccount) {
|
||||
const request = {
|
||||
mediaBlastCampaignId: campaignId,
|
||||
mediaBlastAccountId: acc.id,
|
||||
};
|
||||
const response = await saveMediaBlastCampaignAccount(request);
|
||||
if (response?.error) {
|
||||
error(response.message);
|
||||
}
|
||||
}
|
||||
fetchData();
|
||||
}
|
||||
|
||||
const handleFilter = (id: string, checked: boolean) => {
|
||||
let temp = [...filtered];
|
||||
if (checked) {
|
||||
temp = [...temp, id];
|
||||
} else {
|
||||
temp = temp.filter((a) => a !== id);
|
||||
}
|
||||
if (checked) temp = [...temp, id];
|
||||
else temp = temp.filter((a) => a !== id);
|
||||
setFiltered(temp);
|
||||
console.log("sss", temp);
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
@ -130,20 +179,103 @@ const AccountListTable = () => {
|
|||
<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">
|
||||
<Button color="primary" size="md" className="text-sm">
|
||||
<Icon icon="tdesign:user-add-filled" />
|
||||
Tambah Akun
|
||||
</Button>
|
||||
</Link>
|
||||
{/* <Link href="/admin/broadcast/campaign-list/import">
|
||||
<Button color="success" size="md" className="text-sm">
|
||||
<UserIcon />
|
||||
Import Akun
|
||||
</Button>
|
||||
</Link> */}
|
||||
{/* === Dialog Pilih Akun === */}
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button size="sm" className="text-sm">
|
||||
<Icon icon="tdesign:user-add-filled" className="mr-2" />
|
||||
Pilih Akun
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-w-lg">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Pilih Akun Untuk Campaign Ini</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
<RadioGroup
|
||||
value={accountCategory}
|
||||
onValueChange={(val) => setAccountCategory(val)}
|
||||
className="space-y-3"
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="all-account" id="all-account" />
|
||||
<Label htmlFor="all-account">Semua Akun</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="kategori" id="kategori" />
|
||||
<Label htmlFor="kategori">Kategori</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="custom" id="custom" />
|
||||
<Label htmlFor="custom">Custom</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
|
||||
<div className="mt-4 space-y-4">
|
||||
{accountCategory === "custom" && (
|
||||
<>
|
||||
<Select
|
||||
onValueChange={(val) =>
|
||||
setSelectedAccount([...selectedAccount, { id: val }])
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Pilih akun" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{dataTable.map((acc) => (
|
||||
<SelectItem key={acc.id} value={acc.id}>
|
||||
{acc.accountName}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
{selectedAccount.length < 1 && (
|
||||
<p className="text-sm text-red-500">
|
||||
Pilih minimal 1 akun
|
||||
</p>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{accountCategory === "kategori" && (
|
||||
<Select onValueChange={(val) => setSelectedCategory(val)}>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Pilih kategori" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="umum">Umum</SelectItem>
|
||||
<SelectItem value="polri">Polri</SelectItem>
|
||||
<SelectItem value="ksp">KSP</SelectItem>
|
||||
<SelectItem value="jurnalis">Jurnalis</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
)}
|
||||
|
||||
{accountCategory === "all-account" && (
|
||||
<p className="text-sm text-gray-600">Semua akun dipilih</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<DialogFooter>
|
||||
<Button
|
||||
onClick={saveCampaignAccount}
|
||||
disabled={
|
||||
accountCategory === "custom" && selectedAccount.length < 1
|
||||
}
|
||||
>
|
||||
Simpan
|
||||
</Button>
|
||||
<DialogClose asChild>
|
||||
<Button variant="outline">Batal</Button>
|
||||
</DialogClose>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* === Filter Akun === */}
|
||||
<div className="flex justify-end">
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
|
|
@ -163,65 +295,28 @@ const AccountListTable = () => {
|
|||
</a>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1 overflow-auto max-h-[300px] text-xs custom-scrollbar-table">
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id="accepted"
|
||||
checked={filtered.includes("polri")}
|
||||
onCheckedChange={(e) => handleFilter("polri", Boolean(e))}
|
||||
/>
|
||||
<label
|
||||
htmlFor="accepted"
|
||||
className="text-xs font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
POLRI
|
||||
</label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id="accepted"
|
||||
checked={filtered.includes("jurnalis")}
|
||||
onCheckedChange={(e) =>
|
||||
handleFilter("jurnalis", Boolean(e))
|
||||
}
|
||||
/>
|
||||
<label
|
||||
htmlFor="accepted"
|
||||
className="text-xs font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
JURNALIS
|
||||
</label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id="accepted"
|
||||
checked={filtered.includes("umum")}
|
||||
onCheckedChange={(e) => handleFilter("umum", Boolean(e))}
|
||||
/>
|
||||
<label
|
||||
htmlFor="accepted"
|
||||
className="text-xs font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
UMUM
|
||||
</label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id="accepted"
|
||||
checked={filtered.includes("ksp")}
|
||||
onCheckedChange={(e) => handleFilter("ksp", Boolean(e))}
|
||||
/>
|
||||
<label
|
||||
htmlFor="accepted"
|
||||
className="text-xs font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
KSP
|
||||
</label>
|
||||
</div>
|
||||
{["polri", "jurnalis", "umum", "ksp"].map((cat) => (
|
||||
<div key={cat} className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id={cat}
|
||||
checked={filtered.includes(cat)}
|
||||
onCheckedChange={(e) => handleFilter(cat, Boolean(e))}
|
||||
/>
|
||||
<label
|
||||
htmlFor={cat}
|
||||
className="text-xs font-medium leading-none"
|
||||
>
|
||||
{cat.toUpperCase()}
|
||||
</label>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
|
||||
{/* === Table Data === */}
|
||||
<Table className="overflow-hidden">
|
||||
<TableHeader>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
|
|
@ -263,6 +358,7 @@ const AccountListTable = () => {
|
|||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
||||
<TablePagination
|
||||
table={table}
|
||||
totalData={totalData}
|
||||
|
|
|
|||
|
|
@ -83,7 +83,6 @@ export default function BroadcastCampaignDetail({
|
|||
"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]>([
|
||||
|
|
@ -91,10 +90,8 @@ export default function BroadcastCampaignDetail({
|
|||
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>([]);
|
||||
|
|
@ -104,7 +101,6 @@ export default function BroadcastCampaignDetail({
|
|||
pageIndex: 0,
|
||||
pageSize: parseInt(size || "10"),
|
||||
});
|
||||
|
||||
const pages = page ? parseInt(page) - 1 : 0;
|
||||
const currentPage = page ? parseInt(page) : 1;
|
||||
const pageSize = parseInt(size || "10");
|
||||
|
|
|
|||
|
|
@ -1,59 +1,73 @@
|
|||
"use client";
|
||||
import { Reveal } from "@/components/landing-page/Reveal";
|
||||
import { getCookiesDecrypt } from "@/lib/utils";
|
||||
import { useRouter } from "next/navigation";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { yupResolver } from "@hookform/resolvers/yup";
|
||||
import * as Yup from "yup";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { getInfoProfile, getProfile, getSubjects } from "@/service/auth";
|
||||
import { getInfoProfile, getSubjects } from "@/service/auth";
|
||||
import { close, error, loading, successCallback } from "@/config/swal";
|
||||
import { sendMessage } from "@/service/landing/landing";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { z } from "zod";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useRouter } from "@/i18n/routing";
|
||||
|
||||
interface IFormInput {
|
||||
name: string;
|
||||
email: string;
|
||||
phone?: string | undefined;
|
||||
subjects: string;
|
||||
othersubject?: string | undefined;
|
||||
message: string;
|
||||
}
|
||||
|
||||
const ContactForm = () => {
|
||||
const router = useRouter();
|
||||
const userId = getCookiesDecrypt("uie");
|
||||
const [subjects, setSubjects] = useState<any>();
|
||||
const [subjects, setSubjects] = useState<any[]>([]);
|
||||
const [isOtherActive, setIsOtherActive] = useState(false);
|
||||
const t = useTranslations("LandingPage");
|
||||
|
||||
const form = document.getElementById("form") as HTMLFormElement;
|
||||
|
||||
// Form Handling
|
||||
const validationSchema = Yup.object().shape({
|
||||
name: Yup.string().required("Nama tidak boleh kosong"),
|
||||
email: Yup.string().required("Email tidak boleh kosong"),
|
||||
subjects: Yup.string().required("Subjek tidak boleh kosong"),
|
||||
message: Yup.string().required("Pesan tidak boleh kosong"),
|
||||
const validationSchema = z.object({
|
||||
name: z.string().min(1, "Nama tidak boleh kosong"),
|
||||
email: z.string().email("Email tidak valid"),
|
||||
phone: z.string().optional(),
|
||||
subjects: z.string().min(1, "Subjek tidak boleh kosong"),
|
||||
othersubject: z.string().optional(),
|
||||
message: z.string().min(1, "Pesan tidak boleh kosong"),
|
||||
});
|
||||
|
||||
const formOptions = {
|
||||
resolver: yupResolver(validationSchema),
|
||||
};
|
||||
type IFormInput = z.infer<typeof validationSchema>;
|
||||
|
||||
const { register, handleSubmit, formState, setValue } = useForm(formOptions);
|
||||
|
||||
const { errors } = formState;
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
formState: { errors },
|
||||
setValue,
|
||||
reset,
|
||||
} = useForm<IFormInput>({
|
||||
resolver: zodResolver(validationSchema),
|
||||
});
|
||||
|
||||
// Init state
|
||||
useEffect(() => {
|
||||
async function initState() {
|
||||
const response = await getInfoProfile();
|
||||
const responseSubject = await getSubjects();
|
||||
const profile = response?.data?.data;
|
||||
|
||||
setSubjects(responseSubject?.data?.data);
|
||||
console.log(response);
|
||||
setValue("name", profile?.fullname);
|
||||
setValue("email", profile?.email); // setValue('name', profile?.fullname);
|
||||
// setValue('name', profile?.fullname);
|
||||
setSubjects(responseSubject?.data?.data || []);
|
||||
if (profile) {
|
||||
setValue("name", profile?.fullname || "");
|
||||
setValue("email", profile?.email || "");
|
||||
}
|
||||
}
|
||||
|
||||
initState();
|
||||
}, []);
|
||||
}, [setValue]);
|
||||
|
||||
async function save(data: any) {
|
||||
async function save(data: IFormInput) {
|
||||
loading();
|
||||
|
||||
const finalData = {
|
||||
name: data.name,
|
||||
email: data.email,
|
||||
|
|
@ -65,29 +79,24 @@ const ContactForm = () => {
|
|||
const response = await sendMessage(finalData);
|
||||
if (response?.error) {
|
||||
error(response?.message);
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
close();
|
||||
successCallback("Terima kasih, pesan Anda telah terkirim");
|
||||
// $("#form")[0].onreset();
|
||||
if (form) {
|
||||
form.reset();
|
||||
}
|
||||
reset();
|
||||
}
|
||||
|
||||
async function onSubmit(data: any) {
|
||||
async function onSubmit(data: IFormInput) {
|
||||
if (userId == undefined) {
|
||||
router.push("/auth/login");
|
||||
router.push("/auth");
|
||||
} else {
|
||||
save(data);
|
||||
}
|
||||
}
|
||||
|
||||
const handleSubjects = (e: any) => {
|
||||
const id = e.target.value;
|
||||
|
||||
if (id == "Lainnya") {
|
||||
const handleSubjects = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
if (e.target.value === "Lainnya") {
|
||||
setIsOtherActive(true);
|
||||
} else {
|
||||
setIsOtherActive(false);
|
||||
|
|
@ -95,63 +104,163 @@ const ContactForm = () => {
|
|||
};
|
||||
|
||||
return (
|
||||
<form method="POST" id="form" onSubmit={handleSubmit(onSubmit)} className="max-w-2xl mx-auto bg-white dark:bg-black p-6">
|
||||
<form
|
||||
method="POST"
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
className="max-w-2xl mx-auto bg-white dark:bg-black p-6"
|
||||
>
|
||||
<Reveal>
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-center mb-6">
|
||||
<img src="/assets/icons-contact.png" alt="contact" />
|
||||
<h2 className="ml-4 text-2xl font-bold">{t("contactUs", { defaultValue: "Contact Us" })}</h2>
|
||||
<h2 className="ml-4 text-2xl font-bold">
|
||||
{t("contactUs", { defaultValue: "Contact Us" })}
|
||||
</h2>
|
||||
</div>
|
||||
<h3 className="text-lg font-semibold text-gray-800 dark:text-white mb-1">{t("writeMessage", { defaultValue: "Write Message" })}</h3>
|
||||
<p className="text-sm text-gray-600 dark:text-white mb-6">{t("leaveMessage", { defaultValue: "Leave Message" })}</p>
|
||||
<h3 className="text-lg font-semibold text-gray-800 dark:text-white mb-1">
|
||||
{t("writeMessage", { defaultValue: "Write Message" })}
|
||||
</h3>
|
||||
<p className="text-sm text-gray-600 dark:text-white mb-6">
|
||||
{t("leaveMessage", { defaultValue: "Leave Message" })}
|
||||
</p>
|
||||
|
||||
{/* Form */}
|
||||
<form>
|
||||
<div>
|
||||
{/* Name */}
|
||||
<div className="mb-4">
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-white mb-1">{t("name", { defaultValue: "Name" })}</label>
|
||||
<input type="text" placeholder={t("enterName", { defaultValue: "Enter Name" })} className={`w-full p-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 ${errors.name ? "block" : ""}`} {...register("name")} required />
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-white mb-1">
|
||||
{t("name", { defaultValue: "Name" })}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
placeholder={t("enterName", { defaultValue: "Enter Name" })}
|
||||
className={`w-full p-2 border rounded-md focus:outline-none focus:ring-2 ${
|
||||
errors.name
|
||||
? "border-red-500 focus:ring-red-500"
|
||||
: "border-gray-300 focus:ring-blue-500"
|
||||
}`}
|
||||
{...register("name")}
|
||||
/>
|
||||
{errors.name && (
|
||||
<p className="text-red-500 text-sm">{errors.name.message}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Email */}
|
||||
<div className="mb-4">
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-white mb-1">Email</label>
|
||||
<input type="email" placeholder="name@mail.com" className={`w-full p-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 ${errors.email ? "block" : ""}`} {...register("email")} required />
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-white mb-1">
|
||||
Email
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
placeholder="name@mail.com"
|
||||
className={`w-full p-2 border rounded-md focus:outline-none focus:ring-2 ${
|
||||
errors.email
|
||||
? "border-red-500 focus:ring-red-500"
|
||||
: "border-gray-300 focus:ring-blue-500"
|
||||
}`}
|
||||
{...register("email")}
|
||||
/>
|
||||
{errors.email && (
|
||||
<p className="text-red-500 text-sm">{errors.email.message}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Phone */}
|
||||
<div className="mb-4">
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-white mb-1">{t("number", { defaultValue: "Number" })} (Optional)</label>
|
||||
<input type="text" placeholder={t("enterNumber", { defaultValue: "Enter Number" })} className="w-full p-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" />
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-white mb-1">
|
||||
{t("number", { defaultValue: "Number" })} (Optional)
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
placeholder={t("enterNumber", { defaultValue: "Enter Number" })}
|
||||
className="w-full p-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
{...register("phone")}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Subjects */}
|
||||
<div className="mb-4">
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-white mb-1">{t("subject", { defaultValue: "Subject" })}</label>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-white mb-1">
|
||||
{t("subject", { defaultValue: "Subject" })}
|
||||
</label>
|
||||
<select
|
||||
className={`w-full p-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 ${errors.subjects ? "block" : ""}`}
|
||||
className={`w-full p-2 border rounded-md focus:outline-none focus:ring-2 ${
|
||||
errors.subjects
|
||||
? "border-red-500 focus:ring-red-500"
|
||||
: "border-gray-300 focus:ring-blue-500"
|
||||
}`}
|
||||
{...register("subjects", { onChange: (e) => handleSubjects(e) })}
|
||||
defaultValue=""
|
||||
>
|
||||
<option value="" disabled>
|
||||
{t("selectSubject", { defaultValue: "Select Subject" })}
|
||||
</option>
|
||||
{/* <option value="1">{t("question", { defaultValue: "Question" })}</option>
|
||||
<option value="2">{t("criticism", { defaultValue: "Criticism" })}</option>
|
||||
<option value="3">{t("suggestion", { defaultValue: "Suggestion" })}</option> */}
|
||||
{subjects?.map((list: any) => (
|
||||
<option key={list.id} value={list.title}>
|
||||
{list.title}
|
||||
</option>
|
||||
))}
|
||||
<option value="Lainnya">Lainnya</option>
|
||||
</select>
|
||||
{errors.subjects && (
|
||||
<p className="text-red-500 text-sm">{errors.subjects.message}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Other Subject */}
|
||||
{isOtherActive && (
|
||||
<div className="mb-4">
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-white mb-1">
|
||||
Subjek Lainnya
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Masukkan subjek lainnya"
|
||||
className={`w-full p-2 border rounded-md focus:outline-none focus:ring-2 ${
|
||||
errors.othersubject
|
||||
? "border-red-500 focus:ring-red-500"
|
||||
: "border-gray-300 focus:ring-blue-500"
|
||||
}`}
|
||||
{...register("othersubject")}
|
||||
/>
|
||||
{errors.othersubject && (
|
||||
<p className="text-red-500 text-sm">
|
||||
{errors.othersubject.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Message */}
|
||||
<div className="mb-4">
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-white mb-1">{t("messages", { defaultValue: "Messages" })}</label>
|
||||
<textarea placeholder={t("writeYourMessage", { defaultValue: "Write Your Message" })} rows={4} className="w-full p-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"></textarea>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-white mb-1">
|
||||
{t("messages", { defaultValue: "Messages" })}
|
||||
</label>
|
||||
<textarea
|
||||
placeholder={t("writeYourMessage", {
|
||||
defaultValue: "Write Your Message",
|
||||
})}
|
||||
rows={4}
|
||||
className={`w-full p-2 border rounded-md focus:outline-none focus:ring-2 ${
|
||||
errors.message
|
||||
? "border-red-500 focus:ring-red-500"
|
||||
: "border-gray-300 focus:ring-blue-500"
|
||||
}`}
|
||||
{...register("message")}
|
||||
></textarea>
|
||||
{errors.message && (
|
||||
<p className="text-red-500 text-sm">{errors.message.message}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<button type="submit" className="w-fit bg-blue-500 flex justify-self-end text-white p-2 px-8 rounded-md hover:bg-blue-600 transition">
|
||||
<button
|
||||
type="submit"
|
||||
className="w-fit bg-blue-500 flex justify-self-end text-white p-2 px-8 rounded-md hover:bg-blue-600 transition"
|
||||
>
|
||||
{t("send", { defaultValue: "Send" })}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</Reveal>
|
||||
</form>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -290,7 +290,7 @@ export default function ContentBlast(props: { type: string }) {
|
|||
<Dialog open={openModal}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Email Terkirim</DialogTitle>
|
||||
<DialogTitle>Terkirim !!</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="flex flex-col justify-center items-center gap-3 mb-3 text-sm">
|
||||
<img
|
||||
|
|
|
|||
|
|
@ -43,8 +43,13 @@ export async function getMediaBlastCampaignPage(page: number) {
|
|||
return httpGetInterceptor(url);
|
||||
}
|
||||
|
||||
export async function getMediaBlastAccountPage(page: number, category: string) {
|
||||
const url = `media/blast/account/list?enablePage=1&size=10&page=${page}&category=${category}`;
|
||||
export async function getMediaBlastAccountPage(page: number, category: string, campaignId: string) {
|
||||
const url = `media/blast/account/list?enablePage=1&size=10&page=${page}&category=${category}&campaignId=${campaignId}`;
|
||||
return httpGetInterceptor(url);
|
||||
}
|
||||
|
||||
export async function getMediaBlastCampaignAccountList(page: any, category: string, id: any) {
|
||||
const url = `media/blast/campaign-account/list?enablePage=1&page=${page}&category=${category}&campaignId=${id}`;
|
||||
return httpGetInterceptor(url);
|
||||
}
|
||||
|
||||
|
|
@ -58,6 +63,16 @@ export async function saveMediaBlastCampaign(data: {
|
|||
return httpPostInterceptor(url, data);
|
||||
}
|
||||
|
||||
export async function saveMediaBlastCampaignAccount(data: any) {
|
||||
const url = `media/blast/campaign-account`;
|
||||
return httpPostInterceptor( url, data );
|
||||
}
|
||||
|
||||
export async function deleteMediaBlastCampaignAccount(id: any) {
|
||||
const url = `media/blast/campaign-account?id=${id}`;
|
||||
return httpDeleteInterceptor(url);
|
||||
}
|
||||
|
||||
export async function getMediaBlastCampaignById(id: string) {
|
||||
const url = `media/blast/campaign?id=${id}`;
|
||||
return httpGetInterceptor(url);
|
||||
|
|
|
|||
Loading…
Reference in New Issue