Compare commits
12 Commits
c530639470
...
6e3d01cdc0
| Author | SHA1 | Date |
|---|---|---|
|
|
6e3d01cdc0 | |
|
|
c7eecd40c0 | |
|
|
65e7c9db41 | |
|
|
7b364dfbc9 | |
|
|
b16f19e859 | |
|
|
9853fc7097 | |
|
|
9dc25768a4 | |
|
|
23ff7e5be8 | |
|
|
ea082c80f6 | |
|
|
343a0328d4 | |
|
|
af09a86c48 | |
|
|
421db9c1c3 |
|
|
@ -25,6 +25,7 @@ import { useToast } from "@/components/ui/use-toast";
|
|||
import CustomPagination from "@/components/table/custom-pagination";
|
||||
import { listDataMedia } from "@/service/service/broadcast/broadcast";
|
||||
import { setBanner } from "@/service/service/settings/settings";
|
||||
import { listArticles } from "@/service/landing/landing";
|
||||
|
||||
const ContentListBanner = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -64,7 +65,7 @@ const ContentListBanner = () => {
|
|||
);
|
||||
setBannerCount(banners?.length || 0);
|
||||
|
||||
setBannerCount(data?.length || 0);
|
||||
// setBannerCount(data?.length || 0);
|
||||
} catch (error) {
|
||||
console.error("Error fetching banner count:", error);
|
||||
}
|
||||
|
|
@ -118,38 +119,43 @@ const ContentListBanner = () => {
|
|||
try {
|
||||
loading();
|
||||
|
||||
const res = await listDataMedia(
|
||||
page - 1,
|
||||
showData,
|
||||
searchQuery,
|
||||
categoryFilter?.sort().join(","),
|
||||
statusFilter?.sort().join(","),
|
||||
const res = await listArticles(
|
||||
page,
|
||||
Number(showData),
|
||||
1,
|
||||
undefined,
|
||||
undefined,
|
||||
"createdAt",
|
||||
"",
|
||||
);
|
||||
|
||||
const rawData = res?.data?.data;
|
||||
console.log("RES ARTICLES:", res);
|
||||
|
||||
const contentData = Array.isArray(rawData?.content)
|
||||
? rawData.content
|
||||
: [];
|
||||
let articlesData: any[] = [];
|
||||
|
||||
contentData.forEach((item: any, index: number) => {
|
||||
item.no = (page - 1) * Number(showData) + index + 1;
|
||||
});
|
||||
if (res?.error) {
|
||||
articlesData = [];
|
||||
} else {
|
||||
articlesData = res?.data?.data || [];
|
||||
}
|
||||
|
||||
const contentData = articlesData.map((item: any, index: number) => ({
|
||||
...item,
|
||||
no: (page - 1) * Number(showData) + index + 1,
|
||||
smallThumbnailLink: item.thumbnailUrl, // penting
|
||||
}));
|
||||
|
||||
setData(contentData);
|
||||
setTotalData(rawData?.totalElements ?? 0);
|
||||
setTotalPage(rawData?.totalPages ?? 1);
|
||||
setTotalData(contentData.length);
|
||||
setTotalPage(1); // sementara kalau belum ada totalPages
|
||||
|
||||
close();
|
||||
} catch (error) {
|
||||
close();
|
||||
console.error("Error fetching banner data:", error);
|
||||
setData([]);
|
||||
setTotalData(0);
|
||||
setTotalPage(1);
|
||||
}
|
||||
}
|
||||
|
||||
// async function fetchData() {
|
||||
// try {
|
||||
// loading();
|
||||
|
|
@ -210,20 +216,31 @@ const ContentListBanner = () => {
|
|||
}
|
||||
};
|
||||
|
||||
const handleSelect = (id: number) => {
|
||||
// const handleSelect = (id: number) => {
|
||||
// setSelectedItems((prev) =>
|
||||
// prev.includes(id) ? prev.filter((item) => item !== id) : [...prev, id],
|
||||
// );
|
||||
// };
|
||||
const handleSelect = (id: number, checked: boolean) => {
|
||||
setSelectedItems((prev) =>
|
||||
prev.includes(id) ? prev.filter((item) => item !== id) : [...prev, id],
|
||||
checked ? [...prev, id] : prev.filter((item) => item !== id),
|
||||
);
|
||||
};
|
||||
|
||||
const handleSelectAll = () => {
|
||||
if (selectedItems.length === data.length) {
|
||||
setSelectedItems([]);
|
||||
} else {
|
||||
// const handleSelectAll = () => {
|
||||
// if (selectedItems.length === data.length) {
|
||||
// setSelectedItems([]);
|
||||
// } else {
|
||||
// setSelectedItems(data.map((item: any) => Number(item.id)));
|
||||
// }
|
||||
// };
|
||||
const handleSelectAll = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (e.target.checked) {
|
||||
setSelectedItems(data.map((item: any) => Number(item.id)));
|
||||
} else {
|
||||
setSelectedItems([]);
|
||||
}
|
||||
};
|
||||
|
||||
const { toast } = useToast();
|
||||
|
||||
const handleBanner = async (ids: number[]) => {
|
||||
|
|
@ -410,10 +427,15 @@ const ContentListBanner = () => {
|
|||
{/* Header select all + action */}
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={selectedItems.length === data.length && data.length > 0}
|
||||
onChange={handleSelectAll}
|
||||
/>
|
||||
{/* <Checkbox
|
||||
checked={selectedItems.length === data.length}
|
||||
onCheckedChange={handleSelectAll}
|
||||
/>
|
||||
/> */}
|
||||
<span className="text-black dark:text-white">Pilih Semua</span>
|
||||
</div>
|
||||
{selectedItems.length > 0 && (
|
||||
|
|
@ -431,9 +453,14 @@ const ContentListBanner = () => {
|
|||
className="relative rounded-lg shadow-md overflow-hidden border border-gray-200"
|
||||
>
|
||||
<div className="absolute top-2 left-2 z-10">
|
||||
<Checkbox
|
||||
{/* <Checkbox
|
||||
checked={selectedItems.includes(item.id)}
|
||||
onCheckedChange={() => handleSelect(item.id)}
|
||||
/> */}
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={selectedItems.includes(item.id)}
|
||||
onChange={(e) => handleSelect(item.id, e.target.checked)}
|
||||
/>
|
||||
</div>
|
||||
<img
|
||||
|
|
|
|||
|
|
@ -879,18 +879,18 @@ function TenantSettingsContent() {
|
|||
</p>
|
||||
<Button onClick={() => setIsUserLevelDialogOpen(true)}>
|
||||
<PlusIcon className="h-4 w-4 mr-2" />
|
||||
Create User Level
|
||||
Create User Level
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</Tabs>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function TenantSettingsPage() {
|
||||
return <TenantSettingsPageTable />;
|
||||
}
|
||||
return <TenantSettingsPageTable />;
|
||||
}
|
||||
|
|
@ -88,12 +88,16 @@ export default function SignUp() {
|
|||
return;
|
||||
}
|
||||
|
||||
// Umum dan Jurnalis → gunakan API createUser
|
||||
if (role === "umum" || role === "jurnalis") {
|
||||
if (role === "umum") {
|
||||
await handleCreateUserUmum(e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (role === "jurnalis") {
|
||||
await handleCreateUserJurnalis(e);
|
||||
return;
|
||||
}
|
||||
|
||||
// Kontributor (sementara ikut umum)
|
||||
if (role === "kontributor") {
|
||||
await handleCreateUserKontributor(e);
|
||||
|
|
@ -225,10 +229,10 @@ export default function SignUp() {
|
|||
MySwal.fire("Peringatan", "Password minimal 8 karakter", "warning");
|
||||
return;
|
||||
}
|
||||
if (!userLevelId || !userRoleId) {
|
||||
MySwal.fire("Peringatan", "Level dan Role wajib diisi", "warning");
|
||||
return;
|
||||
}
|
||||
// if (!userLevelId || !userRoleId) {
|
||||
// MySwal.fire("Peringatan", "Level dan Role wajib diisi", "warning");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// ✅ Generate username otomatis
|
||||
const autoUsername =
|
||||
|
|
@ -280,6 +284,98 @@ export default function SignUp() {
|
|||
}
|
||||
};
|
||||
|
||||
const handleCreateUserJurnalis = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
// ✅ VALIDASI
|
||||
if (!fullname.trim()) {
|
||||
MySwal.fire("Peringatan", "Nama lengkap wajib diisi", "warning");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validateEmail(email)) {
|
||||
MySwal.fire("Peringatan", "Email tidak valid", "warning");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validatePassword(password)) {
|
||||
MySwal.fire("Peringatan", "Password minimal 8 karakter", "warning");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!membershipType) {
|
||||
MySwal.fire("Peringatan", "Jenis keanggotaan wajib diisi", "warning");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!certNumber.trim()) {
|
||||
MySwal.fire("Peringatan", "Nomor sertifikasi wajib diisi", "warning");
|
||||
return;
|
||||
}
|
||||
|
||||
// ✅ GENERATE USERNAME
|
||||
const autoUsername =
|
||||
fullname.trim().replace(/\s+/g, "-").toLowerCase() || email.split("@")[0];
|
||||
|
||||
if (!validateUsername(autoUsername)) {
|
||||
MySwal.fire("Peringatan", "Username tidak valid", "warning");
|
||||
return;
|
||||
}
|
||||
|
||||
// ✅ PAYLOAD (SUDAH DISESUAIKAN BACKEND)
|
||||
const payload = {
|
||||
address: "",
|
||||
clientId: "78356d32-52fa-4dfc-b836-6cebf4e3eead",
|
||||
dateOfBirth: "",
|
||||
email,
|
||||
fullName: fullname,
|
||||
genderType: "",
|
||||
identityGroup: "",
|
||||
identityGroupNumber: "",
|
||||
identityNumber: certNumber, // 🔥 penting
|
||||
identityType: "KTP",
|
||||
lastEducation: "",
|
||||
password,
|
||||
phoneNumber: "08123456789", // 🔥 jangan kosong dulu
|
||||
userLevelId: 1,
|
||||
userRoleId: 3, // 🔥 pastikan ini role jurnalis
|
||||
username: autoUsername + "-" + Date.now(),
|
||||
workType: membershipType.toUpperCase(),
|
||||
};
|
||||
|
||||
console.log("📦 PAYLOAD JURNALIS:", payload);
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
|
||||
const res = await createUser(payload);
|
||||
|
||||
if (res?.error) {
|
||||
MySwal.fire("Gagal", res?.message || "Gagal mendaftar", "error");
|
||||
} else {
|
||||
MySwal.fire({
|
||||
title: "Berhasil!",
|
||||
text: "Akun jurnalis berhasil dibuat",
|
||||
icon: "success",
|
||||
showConfirmButton: false,
|
||||
timer: 2000,
|
||||
});
|
||||
|
||||
setTimeout(() => router.push("/auth"), 2000);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("❌ ERROR JURNALIS:", err);
|
||||
|
||||
MySwal.fire(
|
||||
"Error",
|
||||
"Terjadi kesalahan server saat registrasi jurnalis",
|
||||
"error",
|
||||
);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const validateTenantForm = () => {
|
||||
const errors: any = {};
|
||||
|
||||
|
|
@ -592,13 +688,13 @@ export default function SignUp() {
|
|||
/>
|
||||
|
||||
{/* Email */}
|
||||
<Input
|
||||
{/* <Input
|
||||
type="email"
|
||||
required
|
||||
placeholder="Email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
/>
|
||||
/> */}
|
||||
|
||||
{/* Password */}
|
||||
<div className="relative">
|
||||
|
|
@ -655,6 +751,25 @@ export default function SignUp() {
|
|||
{/* Jurnalis: Select Keanggotaan */}
|
||||
{role === "jurnalis" && (
|
||||
<div className="mb-4 space-y-4">
|
||||
{/* Nama Lengkap */}
|
||||
<Input
|
||||
type="text"
|
||||
required
|
||||
placeholder="Nama Lengkap"
|
||||
value={fullname}
|
||||
onChange={(e) => setFullname(e.target.value)}
|
||||
/>
|
||||
|
||||
{/* Username (auto generated) */}
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="Username (otomatis dari nama)"
|
||||
value={username}
|
||||
readOnly
|
||||
className="bg-gray-100 text-gray-700 cursor-not-allowed"
|
||||
/>
|
||||
|
||||
{/* Jenis Keanggotaan */}
|
||||
<select
|
||||
required
|
||||
className="w-full border border-gray-300 rounded-md p-2 text-sm"
|
||||
|
|
@ -662,17 +777,11 @@ export default function SignUp() {
|
|||
onChange={(e) => setMembershipType(e.target.value)}
|
||||
>
|
||||
<option value="">Pilih jenis keanggotaan</option>
|
||||
<option value="pwi">
|
||||
PWI (Persatuan Wartawan Indonesia)
|
||||
</option>
|
||||
<option value="ijti">
|
||||
IJTI (Ikatan Jurnalis Televisi Indonesia)
|
||||
</option>
|
||||
<option value="pfi">PFI (Pewarta Foto Indonesia)</option>
|
||||
<option value="aji">
|
||||
AJI (Asosiasi Jurnalis Indonesia)
|
||||
</option>
|
||||
<option value="lainnya">Identitas Lainnya</option>
|
||||
<option value="pwi">PWI</option>
|
||||
<option value="ijti">IJTI</option>
|
||||
<option value="pfi">PFI</option>
|
||||
<option value="aji">AJI</option>
|
||||
<option value="lainnya">Lainnya</option>
|
||||
</select>
|
||||
|
||||
{/* Nomor Sertifikasi */}
|
||||
|
|
@ -683,6 +792,29 @@ export default function SignUp() {
|
|||
value={certNumber}
|
||||
onChange={(e) => setCertNumber(e.target.value)}
|
||||
/>
|
||||
|
||||
{/* Password */}
|
||||
<div className="relative">
|
||||
<Input
|
||||
type={isVisible ? "text" : "password"}
|
||||
required
|
||||
placeholder="Password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
className="pr-10"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={toggleVisibility}
|
||||
className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-500"
|
||||
>
|
||||
{isVisible ? (
|
||||
<EyeSlashFilledIcon className="h-4 w-4" />
|
||||
) : (
|
||||
<EyeFilledIcon className="h-4 w-4" />
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
|
|||
|
|
@ -76,7 +76,6 @@ export default function Navbar() {
|
|||
const fullname = Cookies.get("ufne");
|
||||
|
||||
return (
|
||||
<RevealT>
|
||||
<header className="relative max-w-[1400px] mx-auto flex items-center justify-between px-4 py-3 border-b bg-white dark:bg-default-50 z-50">
|
||||
<div className="flex flex-row items-center justify-between space-x-4 z-10">
|
||||
<Menu
|
||||
|
|
@ -404,6 +403,5 @@ export default function Navbar() {
|
|||
</div>
|
||||
)}
|
||||
</header>
|
||||
</RevealT>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -250,7 +250,7 @@ export function getMenuList(pathname: string, t: any): Group[] {
|
|||
label: "Banner",
|
||||
active: pathname === "/admin/settings/banner",
|
||||
icon: "heroicons:arrow-trending-up",
|
||||
children: [],
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
"target": "es2019",
|
||||
"sourceMap": true,
|
||||
"allowJs": true,
|
||||
"moduleResolution": "node",
|
||||
"moduleResolution": "bundler",
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": [
|
||||
|
|
|
|||
Loading…
Reference in New Issue