[QUDO-57,QUDO-56] feat:Check update profil pengguna,Check form register dan ubah password
This commit is contained in:
parent
12994688a1
commit
1b924d1790
|
|
@ -207,7 +207,7 @@ const MediaOnlineTable = () => {
|
|||
</div>
|
||||
|
||||
<div className="flex justify-between ">
|
||||
<Link href="/admin/broadcast/campaign-list">
|
||||
<Link href="/admin/media-tracking/media-online/create">
|
||||
<Button color="primary" size="md" className="text-sm mr-3">
|
||||
Tambah Media Online
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import FormTaskTa from "@/components/form/task-ta/task-ta-form";
|
||||
import FormAskExpert from "@/components/form/shared/ask-expert-form";
|
||||
import FormDoItYourself from "@/components/form/shared/do-it-yourself-form";
|
||||
import FormMediaOnline from "@/components/form/media-tracking/media-tracking-form";
|
||||
|
||||
const MediaOnlineCreatePage = () => {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<div className="space-y-4">
|
||||
<FormMediaOnline />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MediaOnlineCreatePage;
|
||||
|
|
@ -43,16 +43,42 @@ const columns: ColumnDef<any>[] = [
|
|||
header: "Tanggal",
|
||||
cell: ({ row }) => <span>{row.getValue("categoryName")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "title",
|
||||
header: "Media Online",
|
||||
cell: ({ row }) => <span>{row.getValue("title")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "link",
|
||||
header: "Link Berita",
|
||||
cell: ({ row }) => <span>{row.getValue("categoryName")}</span>,
|
||||
},
|
||||
{
|
||||
id: "actions",
|
||||
accessorKey: "action",
|
||||
header: "Aksi",
|
||||
enableHiding: false,
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
className="bg-transparent ring-offset-transparent hover:bg-transparent hover:ring-0 hover:ring-transparent"
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<MoreVertical className="h-4 w-4 text-default-800" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0" align="end">
|
||||
<Link
|
||||
href={`/admin/media-tracking/tb-news/detail/${row.original.id}`}
|
||||
>
|
||||
<DropdownMenuItem className="p-2 border-b text-default-700 group focus:bg-default focus:text-primary-foreground rounded-none">
|
||||
<Eye className="w-4 h-4 me-1.5" />
|
||||
View
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export default columns;
|
||||
|
|
|
|||
|
|
@ -66,6 +66,15 @@ import { Checkbox } from "@/components/ui/checkbox";
|
|||
import { close, loading } from "@/config/swal";
|
||||
import { Link } from "@/i18n/routing";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import { link } from "fs";
|
||||
|
||||
const NewsTable = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -80,6 +89,7 @@ const NewsTable = () => {
|
|||
[]
|
||||
);
|
||||
const [showTable, setShowTable] = React.useState(false);
|
||||
const [link, setLink] = React.useState("");
|
||||
const [columnVisibility, setColumnVisibility] =
|
||||
React.useState<VisibilityState>({});
|
||||
const [rowSelection, setRowSelection] = React.useState({});
|
||||
|
|
@ -204,100 +214,99 @@ const NewsTable = () => {
|
|||
|
||||
return (
|
||||
<div className="w-full overflow-x-auto bg-white p-4 rounded-sm space-y-3 border">
|
||||
<div className="flex justify-between mb-10 items-center">
|
||||
<div className="flex justify-between items-center">
|
||||
<p className="text-xl font-medium text-default-900">
|
||||
Tracking Berita hari ini!
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<Label>
|
||||
Masukan Link <span className="text-red-500">*</span>
|
||||
</Label>
|
||||
<Input></Input>
|
||||
<p className="text-sm">Sisa kuota harian: 30 Artikel</p>
|
||||
</div>
|
||||
{!showTable && (
|
||||
<div className="flex justify-end">
|
||||
<Button
|
||||
color="primary"
|
||||
size="md"
|
||||
className="text-sm mr-3"
|
||||
variant="outline"
|
||||
>
|
||||
Batal
|
||||
</Button>
|
||||
<Button
|
||||
color="primary"
|
||||
size="md"
|
||||
className="text-sm mr-3"
|
||||
onClick={() => setShowTable(true)}
|
||||
>
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button className="bg-blue-600" size="md">
|
||||
Tracking Berita
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
{showTable && (
|
||||
<>
|
||||
<Table className="overflow-hidden mt-4">
|
||||
<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} 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 className="flex justify-end mt-4">
|
||||
<Button
|
||||
color="primary"
|
||||
size="md"
|
||||
className="text-sm mr-3"
|
||||
onClick={() => setShowTable(false)}
|
||||
>
|
||||
Tracking Berita Baru
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="sm:max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Form Tracking Berita</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="grid gap-4 py-4">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="link" className="text-sm font-medium">
|
||||
Masukkan Link <span className="text-red-500">*</span>
|
||||
</Label>
|
||||
<Input
|
||||
id="link"
|
||||
placeholder="Masukkan Link disini!"
|
||||
value={link}
|
||||
onChange={(e) => setLink(e.target.value)}
|
||||
/>
|
||||
<p className="text-sm text-muted-foreground mt-1">
|
||||
Sisa Kuota Harian: 5 Kata Kunci
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<DialogFooter className="flex justify-end gap-2">
|
||||
<Button variant="outline">Batal</Button>
|
||||
<Button className="bg-blue-600 text-white">Tracking Berita</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
<Table className="overflow-hidden mt-4">
|
||||
<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} 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 className="flex justify-end mt-4">
|
||||
<Button
|
||||
color="primary"
|
||||
size="md"
|
||||
className="text-sm mr-3"
|
||||
onClick={() => setShowTable(false)}
|
||||
>
|
||||
Tracking Berita Baru
|
||||
</Button>
|
||||
</div>
|
||||
{/* </>
|
||||
)} */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
import SiteBreadcrumb from "@/components/site-breadcrumb";
|
||||
import NewsTable from "../../component/table";
|
||||
import NewsDetailTable from "../component/table";
|
||||
|
||||
export default function DetailNews() {
|
||||
return (
|
||||
<div>
|
||||
<SiteBreadcrumb />
|
||||
<NewsDetailTable />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
import * as React from "react";
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
|
||||
import { Eye, MoreVertical, SquarePen, Trash2 } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuItem,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import {
|
||||
formatDateToIndonesian,
|
||||
getOnlyDate,
|
||||
htmlToString,
|
||||
} from "@/utils/globals";
|
||||
import { Link, useRouter } from "@/i18n/routing";
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from "@/components/ui/accordion";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Collapsible, CollapsibleContent } from "@/components/ui/collapsible";
|
||||
|
||||
const columns: ColumnDef<any>[] = [
|
||||
{
|
||||
accessorKey: "no",
|
||||
header: "No",
|
||||
cell: ({ row }) => <span>{row.getValue("no")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "mediaOnline",
|
||||
header: "Media Online",
|
||||
cell: ({ row }) => <span>{row.getValue("categoryName")}</span>,
|
||||
},
|
||||
{
|
||||
accessorKey: "link",
|
||||
header: "Link Berita",
|
||||
cell: ({ row }) => <span>{row.getValue("categoryName")}</span>,
|
||||
},
|
||||
];
|
||||
|
||||
export default columns;
|
||||
|
|
@ -0,0 +1,263 @@
|
|||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import {
|
||||
ColumnDef,
|
||||
ColumnFiltersState,
|
||||
PaginationState,
|
||||
SortingState,
|
||||
VisibilityState,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
getFilteredRowModel,
|
||||
getPaginationRowModel,
|
||||
getSortedRowModel,
|
||||
useReactTable,
|
||||
} from "@tanstack/react-table";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||||
import {
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
Eye,
|
||||
MoreVertical,
|
||||
Search,
|
||||
SquarePen,
|
||||
Trash2,
|
||||
TrendingDown,
|
||||
TrendingUp,
|
||||
UserIcon,
|
||||
} from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuRadioGroup,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { InputGroup, InputGroupText } from "@/components/ui/input-group";
|
||||
import { paginationBlog } from "@/service/blog/blog";
|
||||
import { ticketingPagination } from "@/service/ticketing/ticketing";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import TablePagination from "@/components/table/table-pagination";
|
||||
import columns from "./column";
|
||||
import { getPlanningPagination } from "@/service/agenda-setting/agenda-setting";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { listDataMedia } from "@/service/broadcast/broadcast";
|
||||
import { listEnableCategory } from "@/service/content/content";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { close, loading } from "@/config/swal";
|
||||
import { Link } from "@/i18n/routing";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import { link } from "fs";
|
||||
|
||||
const NewsDetailTable = () => {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const [search, setSearch] = React.useState("");
|
||||
const [showData, setShowData] = React.useState("10");
|
||||
const [categories, setCategories] = React.useState<any>();
|
||||
const [dataTable, setDataTable] = React.useState<any[]>([]);
|
||||
const [totalData, setTotalData] = React.useState<number>(1);
|
||||
const [sorting, setSorting] = React.useState<SortingState>([]);
|
||||
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
|
||||
[]
|
||||
);
|
||||
const [showTable, setShowTable] = React.useState(false);
|
||||
const [link, setLink] = React.useState("");
|
||||
const [columnVisibility, setColumnVisibility] =
|
||||
React.useState<VisibilityState>({});
|
||||
const [rowSelection, setRowSelection] = React.useState({});
|
||||
const [pagination, setPagination] = React.useState<PaginationState>({
|
||||
pageIndex: 0,
|
||||
pageSize: Number(showData),
|
||||
});
|
||||
const [categoryFilter, setCategoryFilter] = React.useState<number[]>([]);
|
||||
const [statusFilter, setStatusFilter] = React.useState<number[]>([]);
|
||||
const [page, setPage] = React.useState(1);
|
||||
const [totalPage, setTotalPage] = React.useState(1);
|
||||
const table = useReactTable({
|
||||
data: dataTable,
|
||||
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,
|
||||
},
|
||||
});
|
||||
|
||||
let typingTimer: any;
|
||||
const doneTypingInterval = 1500;
|
||||
|
||||
// const handleKeyUp = () => {
|
||||
// clearTimeout(typingTimer);
|
||||
// typingTimer = setTimeout(doneTyping, doneTypingInterval);
|
||||
// };
|
||||
|
||||
const handleKeyDown = () => {
|
||||
clearTimeout(typingTimer);
|
||||
};
|
||||
|
||||
// async function doneTyping() {
|
||||
// fetchData();
|
||||
// }
|
||||
|
||||
React.useEffect(() => {
|
||||
const pageFromUrl = searchParams?.get("page");
|
||||
if (pageFromUrl) {
|
||||
setPage(Number(pageFromUrl));
|
||||
}
|
||||
}, [searchParams]);
|
||||
|
||||
// React.useEffect(() => {
|
||||
// fetchData();
|
||||
// setPagination({
|
||||
// pageIndex: 0,
|
||||
// pageSize: Number(showData),
|
||||
// });
|
||||
// }, [page, showData]);
|
||||
|
||||
// async function fetchData() {
|
||||
// try {
|
||||
// loading();
|
||||
// const res = await listDataMedia(
|
||||
// page - 1,
|
||||
// showData,
|
||||
// search,
|
||||
// categoryFilter?.sort().join(","),
|
||||
// statusFilter?.sort().join(",")
|
||||
// );
|
||||
// const data = res?.data?.data;
|
||||
// const contentData = data?.content;
|
||||
// contentData.forEach((item: any, index: number) => {
|
||||
// item.no = (page - 1) * Number(showData) + index + 1;
|
||||
// });
|
||||
|
||||
// console.log("contentData : ", data);
|
||||
|
||||
// setDataTable(contentData);
|
||||
// setTotalData(data?.totalElements);
|
||||
// setTotalPage(data?.totalPages);
|
||||
// close();
|
||||
// } catch (error) {
|
||||
// console.error("Error fetching tasks:", error);
|
||||
// }
|
||||
// }
|
||||
|
||||
React.useEffect(() => {
|
||||
getCategories();
|
||||
}, []);
|
||||
|
||||
async function getCategories() {
|
||||
const category = await listEnableCategory("");
|
||||
const resCategory = category?.data?.data?.content;
|
||||
setCategories(resCategory);
|
||||
}
|
||||
|
||||
const handleChange = (type: string, id: number, checked: boolean) => {
|
||||
if (type === "category") {
|
||||
if (checked) {
|
||||
const temp: number[] = [...categoryFilter];
|
||||
temp.push(id);
|
||||
setCategoryFilter(temp);
|
||||
} else {
|
||||
const temp = categoryFilter.filter((a) => a !== id);
|
||||
setCategoryFilter(temp);
|
||||
}
|
||||
} else {
|
||||
if (checked) {
|
||||
const temp: number[] = [...statusFilter];
|
||||
temp.push(id);
|
||||
setStatusFilter(temp);
|
||||
} else {
|
||||
const temp = statusFilter.filter((a) => a !== id);
|
||||
setStatusFilter(temp);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full overflow-x-auto bg-white p-4 rounded-sm space-y-3 border">
|
||||
<Table className="overflow-hidden mt-4">
|
||||
<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} 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>
|
||||
);
|
||||
};
|
||||
|
||||
export default NewsDetailTable;
|
||||
|
|
@ -10,13 +10,14 @@ import * as z from "zod";
|
|||
import Swal from "sweetalert2";
|
||||
import { getBlog, postBlog } from "@/service/blog/blog";
|
||||
import { id } from "date-fns/locale";
|
||||
import router from "next/router";
|
||||
import { getInfoProfile, saveUser, setupPassword } from "@/service/auth";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Link } from "@/components/navigation";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { close, error, loading } from "@/lib/swal";
|
||||
|
||||
const profileSchema = z.object({
|
||||
password: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
|
|
@ -31,6 +32,7 @@ type Detail = {
|
|||
};
|
||||
|
||||
const ChangePassword: React.FC = () => {
|
||||
const router = useRouter();
|
||||
const MySwal = withReactContent(Swal);
|
||||
const [detail, setDetail] = useState<Detail>();
|
||||
const [refresh, setRefresh] = useState(false);
|
||||
|
|
@ -59,26 +61,52 @@ const ChangePassword: React.FC = () => {
|
|||
}, []);
|
||||
|
||||
const save = async (data: ProfileSchema) => {
|
||||
const requestData = {
|
||||
...data,
|
||||
// userId: detail?.userKeycloakId,
|
||||
password: data.password,
|
||||
retypePassword: detail?.retypePassword,
|
||||
};
|
||||
if (data.password != null && data.password == data.retypePassword) {
|
||||
loading();
|
||||
const newData = {
|
||||
// userId: detail?.userKeycloakId,
|
||||
password: data.password,
|
||||
retypePassword: detail?.retypePassword,
|
||||
};
|
||||
|
||||
const response = await setupPassword(requestData);
|
||||
console.log("Form Data Submitted:", requestData);
|
||||
console.log("response", response);
|
||||
const response = await setupPassword(newData);
|
||||
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
text: "Data berhasil disimpan.",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then(() => {
|
||||
router.push("/en/auth");
|
||||
});
|
||||
close();
|
||||
if (response?.error) {
|
||||
error(response.message);
|
||||
return false;
|
||||
}
|
||||
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
text: "Data berhasil disimpan.",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then(() => {
|
||||
router.push("/in/auth");
|
||||
});
|
||||
}
|
||||
// const requestData = {
|
||||
// ...data,
|
||||
// // userId: detail?.userKeycloakId,
|
||||
// password: data.password,
|
||||
// retypePassword: detail?.retypePassword,
|
||||
// };
|
||||
|
||||
// const response = await setupPassword(requestData);
|
||||
// console.log("Form Data Submitted:", requestData);
|
||||
// console.log("response", response);
|
||||
|
||||
// MySwal.fire({
|
||||
// title: "Sukses",
|
||||
// text: "Data berhasil disimpan.",
|
||||
// icon: "success",
|
||||
// confirmButtonColor: "#3085d6",
|
||||
// confirmButtonText: "OK",
|
||||
// }).then(() => {
|
||||
// router.push("/in/auth");
|
||||
// });
|
||||
};
|
||||
|
||||
const onSubmit = (data: ProfileSchema) => {
|
||||
|
|
@ -107,13 +135,19 @@ const ChangePassword: React.FC = () => {
|
|||
|
||||
<div className="flex justify-center gap-4 mb-8">
|
||||
<Link href={"/profile"}>
|
||||
<button className="border border-red-700 text-red-700 px-4 py-2 rounded">{t("userProfile")}</button>
|
||||
<button className="border border-red-700 text-red-700 px-4 py-2 rounded">
|
||||
{t("userProfile")}
|
||||
</button>
|
||||
</Link>
|
||||
<Link href={"/profile/change-profile"}>
|
||||
<button className="border border-red-700 text-red-700 px-4 py-2 rounded">{t("changePhoto")}</button>
|
||||
<button className="border border-red-700 text-red-700 px-4 py-2 rounded">
|
||||
{t("changePhoto")}
|
||||
</button>
|
||||
</Link>
|
||||
<Link href={"/profile/change-password"}>
|
||||
<button className="bg-red-700 text-white px-4 py-2 rounded">{t("changePass")}</button>
|
||||
<button className="bg-red-700 text-white px-4 py-2 rounded">
|
||||
{t("changePass")}
|
||||
</button>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
|
|
@ -126,20 +160,55 @@ const ChangePassword: React.FC = () => {
|
|||
{t("password")}
|
||||
<span className="text-red-500">*</span>
|
||||
</Label>
|
||||
<Controller control={control} name="password" render={({ field }) => <Input size="md" type="password" defaultValue={field.value} onChange={field.onChange} placeholder={t("inputPass")} />} />
|
||||
{errors.password?.message && <p className="text-red-400 text-sm">{errors.password.message}</p>}
|
||||
<Controller
|
||||
control={control}
|
||||
name="password"
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
size="md"
|
||||
type="password"
|
||||
defaultValue={field.value}
|
||||
onChange={field.onChange}
|
||||
placeholder={t("inputPass")}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.password?.message && (
|
||||
<p className="text-red-400 text-sm">
|
||||
{errors.password.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="mb-4">
|
||||
<Label>
|
||||
{t("confirmPass")}
|
||||
<span className="text-red-500">*</span>
|
||||
</Label>
|
||||
<Controller control={control} name="retypePassword" render={({ field }) => <Input size="md" type="password" defaultValue={field.value} onChange={field.onChange} placeholder={t("samePass")} />} />
|
||||
{errors.retypePassword?.message && <p className="text-red-400 text-sm">{errors.retypePassword.message}</p>}
|
||||
<Controller
|
||||
control={control}
|
||||
name="retypePassword"
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
size="md"
|
||||
type="password"
|
||||
defaultValue={field.value}
|
||||
onChange={field.onChange}
|
||||
placeholder={t("samePass")}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.retypePassword?.message && (
|
||||
<p className="text-red-400 text-sm">
|
||||
{errors.retypePassword.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<div className="mt-4">
|
||||
<button type="submit" className="bg-red-700 text-white px-6 py-2 rounded hover:bg-red-800 focus:outline-none focus:ring focus:ring-red-300">
|
||||
<button
|
||||
type="submit"
|
||||
className="bg-red-700 text-white px-6 py-2 rounded hover:bg-red-800 focus:outline-none focus:ring focus:ring-red-300"
|
||||
>
|
||||
{t("save")}
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,256 @@
|
|||
"use client";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { useForm, Controller } from "react-hook-form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import * as z from "zod";
|
||||
import Swal from "sweetalert2";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import { useParams, useRouter } from "next/navigation";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||
import JoditEditor from "jodit-react";
|
||||
import {
|
||||
createTask,
|
||||
createTaskTa,
|
||||
getTask,
|
||||
getUserLevelForAssignments,
|
||||
getUserLevelForExpert,
|
||||
} from "@/service/task";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import { CalendarIcon, ChevronDown, ChevronUp, Trash2 } from "lucide-react";
|
||||
import { AudioRecorder } from "react-audio-voice-recorder";
|
||||
import FileUploader from "@/components/form/shared/file-uploader";
|
||||
import { Upload } from "tus-js-client";
|
||||
import { error } from "@/config/swal";
|
||||
import { getCsrfToken } from "@/service/auth";
|
||||
import { loading } from "@/lib/swal";
|
||||
import { useTranslations } from "next-intl";
|
||||
import dynamic from "next/dynamic";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { Calendar } from "@/components/ui/calendar";
|
||||
import { addDays, format, setDate } from "date-fns";
|
||||
import { DateRange } from "react-day-picker";
|
||||
import TimePicker from "react-time-picker";
|
||||
import "react-time-picker/dist/TimePicker.css";
|
||||
import "react-clock/dist/Clock.css";
|
||||
import {
|
||||
AdministrationLevelList,
|
||||
getListCompetencies,
|
||||
getListExperiences,
|
||||
} from "@/service/management-user/management-user";
|
||||
import { Link } from "@/i18n/routing";
|
||||
|
||||
const taskSchema = z.object({
|
||||
title: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
url: z.string().min(2, {
|
||||
message: "Narasi Penugasan harus lebih dari 2 karakter.",
|
||||
}),
|
||||
assign: z.string().min(1, { message: "Judul diperlukan" }),
|
||||
});
|
||||
|
||||
interface FileWithPreview extends File {
|
||||
preview: string;
|
||||
}
|
||||
|
||||
export type taskDetail = {
|
||||
id: number;
|
||||
title: string;
|
||||
fileTypeOutput: string;
|
||||
assignedToTopLevel: string;
|
||||
url: string;
|
||||
};
|
||||
|
||||
const CustomEditor = dynamic(
|
||||
() => {
|
||||
return import("@/components/editor/custom-editor");
|
||||
},
|
||||
{ ssr: false }
|
||||
);
|
||||
|
||||
export default function FormMediaOnline() {
|
||||
const MySwal = withReactContent(Swal);
|
||||
const router = useRouter();
|
||||
const editor = useRef(null);
|
||||
type TaskSchema = z.infer<typeof taskSchema>;
|
||||
const { id } = useParams() as { id: string };
|
||||
console.log(id);
|
||||
const [taskType, setTaskType] = useState<string>("atensi-khusus");
|
||||
const [broadcastType, setBroadcastType] = useState<string>("");
|
||||
const [type, setType] = useState<string>("1");
|
||||
const [selectedTarget, setSelectedTarget] = useState("3,4");
|
||||
const [detail, setDetail] = useState<taskDetail>();
|
||||
const [listExpert, setListExpert] = useState<any[]>([]);
|
||||
const [checkedLevels, setCheckedLevels] = useState<Set<number>>(new Set());
|
||||
const [expandedPolda, setExpandedPolda] = useState([{}]);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [audioFile, setAudioFile] = useState<File | null>(null);
|
||||
const [isRecording, setIsRecording] = useState(false);
|
||||
const [timer, setTimer] = useState<number>(120);
|
||||
|
||||
const t = useTranslations("Form");
|
||||
|
||||
const {
|
||||
register,
|
||||
control,
|
||||
setValue,
|
||||
handleSubmit,
|
||||
formState: { errors },
|
||||
} = useForm<TaskSchema>({
|
||||
resolver: zodResolver(taskSchema),
|
||||
mode: "all",
|
||||
});
|
||||
|
||||
// };
|
||||
|
||||
const save = async (data: TaskSchema) => {
|
||||
const requestData: {
|
||||
id?: number;
|
||||
title: string;
|
||||
assignedToUsers: any;
|
||||
url: any;
|
||||
} = {
|
||||
...data,
|
||||
assignedToUsers: data.assign,
|
||||
url: data.url,
|
||||
title: data.title,
|
||||
};
|
||||
|
||||
const response = await createTaskTa(requestData);
|
||||
|
||||
console.log("Form Data Submitted:", requestData);
|
||||
console.log("response", response);
|
||||
|
||||
const id = response?.data?.data.id;
|
||||
};
|
||||
|
||||
const onSubmit = (data: TaskSchema) => {
|
||||
MySwal.fire({
|
||||
title: "Simpan Data",
|
||||
text: "Apakah Anda yakin ingin menyimpan data ini?",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "Simpan",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
save(data);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const successSubmit = (redirect: string) => {
|
||||
MySwal.fire({
|
||||
title: "Sukses",
|
||||
text: "Data berhasil disimpan.",
|
||||
icon: "success",
|
||||
confirmButtonColor: "#3085d6",
|
||||
confirmButtonText: "OK",
|
||||
}).then(() => {
|
||||
router.push(redirect);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<div className="px-6 py-6">
|
||||
<p className="text-xl mb-3">{t("data-media")}</p>
|
||||
<p className="text-lg font-semibold mb-3">{t("form-media")}</p>
|
||||
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<div className="gap-5 mb-5">
|
||||
{/* Input Title */}
|
||||
<div className="space-y-2">
|
||||
<Label>{t("title-media-online")}</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
name="title"
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
size="md"
|
||||
type="text"
|
||||
value={detail?.title}
|
||||
onChange={field.onChange}
|
||||
placeholder="Enter Title"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.title?.message && (
|
||||
<p className="text-red-400 text-sm">{errors.title.message}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="mt-5 space-y-2">
|
||||
<Label>{t("url")}</Label>
|
||||
<Controller
|
||||
control={control}
|
||||
name="url"
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
size="md"
|
||||
type="text"
|
||||
value={detail?.url}
|
||||
onChange={field.onChange}
|
||||
placeholder="Enter Title"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.title?.message && (
|
||||
<p className="text-red-400 text-sm">{errors.title.message}</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-5 space-y-2">
|
||||
<Label>{t("coverage-area")}</Label>
|
||||
<Select onValueChange={setSelectedTarget}>
|
||||
<SelectTrigger size="md">
|
||||
<SelectValue placeholder="Choose" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="3,4">Semua Pengguna</SelectItem>
|
||||
<SelectItem value="4">Kontributor</SelectItem>
|
||||
<SelectItem value="3">Approver</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row items-center justify-end gap-3">
|
||||
<div className="mt-4 ">
|
||||
<Link href={"/admin/media-tracking/media-online"}>
|
||||
<Button color="primary" variant={"outline"}>
|
||||
{t("cancel")}
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="mt-4">
|
||||
<Button type="submit" color="primary">
|
||||
{t("submit")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,5 +1,5 @@
|
|||
"use client";
|
||||
import React, { useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { Input } from "@/components/ui/input";
|
||||
|
|
@ -9,7 +9,7 @@ import { Icon } from "@/components/ui/icon";
|
|||
import { useForm, SubmitHandler } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { z } from "zod";
|
||||
import { cn, setCookiesEncrypt } from "@/lib/utils";
|
||||
import { cn, getCookiesDecrypt, setCookiesEncrypt } from "@/lib/utils";
|
||||
import { Eye, EyeOff, Loader2 } from "lucide-react";
|
||||
import {
|
||||
getProfile,
|
||||
|
|
@ -32,6 +32,13 @@ import {
|
|||
} from "@/components/ui/input-otp";
|
||||
import { error, loading } from "@/config/swal";
|
||||
import { data } from "jquery";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogFooter,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import { getUserNotifications, listRole } from "@/service/landing/landing";
|
||||
|
||||
// Schema validasi menggunakan zod
|
||||
const schema = z.object({
|
||||
|
|
@ -58,11 +65,16 @@ const LoginForm = () => {
|
|||
const [userIdentity] = useState();
|
||||
const [email, setEmail] = useState();
|
||||
const [category, setCategory] = useState("5");
|
||||
const roleId = getCookiesDecrypt("urie");
|
||||
|
||||
const [username, setUsername] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [oldEmail, setOldEmail] = useState("");
|
||||
const [oldEmailValidate, setOldEmailValidate] = useState("");
|
||||
const [role, setRole] = useState<any>();
|
||||
const [menuActive, setMenuActive] = useState<string>();
|
||||
const [notifications, setNotifications] = useState([]);
|
||||
const [notificationsUpdate, setNotificationsUpdate] = useState([]);
|
||||
const [newEmail, setNewEmail] = useState("");
|
||||
const [newEmailValidate, setNewEmailValidate] = useState("");
|
||||
const [otpValidate, setOtpValidate] = useState("");
|
||||
|
|
@ -341,6 +353,36 @@ const LoginForm = () => {
|
|||
}
|
||||
};
|
||||
|
||||
let menu = "";
|
||||
|
||||
useEffect(() => {
|
||||
async function initState() {
|
||||
setMenuActive(menu);
|
||||
const res = await listRole();
|
||||
setRole(res?.data?.data);
|
||||
}
|
||||
|
||||
async function getNotif() {
|
||||
if (roleId != undefined) {
|
||||
const response = await getUserNotifications(0, 2);
|
||||
setNotifications(response?.data?.data?.content);
|
||||
console.log("respon:", response);
|
||||
}
|
||||
}
|
||||
|
||||
async function getNotifUpdate() {
|
||||
if (roleId != undefined) {
|
||||
const response = await getUserNotifications(0, 3);
|
||||
setNotificationsUpdate(response?.data?.data?.content);
|
||||
console.log("Notiffff:", response);
|
||||
}
|
||||
}
|
||||
|
||||
initState();
|
||||
getNotif();
|
||||
getNotifUpdate();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="mt-5 2xl:mt-7 space-y-4">
|
||||
{step === 1 ? (
|
||||
|
|
@ -350,7 +392,50 @@ const LoginForm = () => {
|
|||
{t("logInPlease")}
|
||||
</h4>
|
||||
<div className="text-default-500 text-base">
|
||||
{t("acc")} <span className="text-red-500">{t("reg")}</span>
|
||||
{t("acc")}
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<span className="w-full lg:w-fit px-2 h-8 text-red-500 hover:cursor-pointer">
|
||||
{t("register")}
|
||||
</span>
|
||||
</DialogTrigger>
|
||||
<DialogContent size="sm" className="sm:max-w-[425px]">
|
||||
<div className="flex flex-col w-full gap-1">
|
||||
<p className="text-lg font-semibold text-center">
|
||||
{t("categoryReg")}
|
||||
</p>
|
||||
<p className="text-base text-center">{t("selectOne")}</p>
|
||||
</div>
|
||||
<div>
|
||||
{role?.map((row: any) => (
|
||||
<div key={row.id}>
|
||||
<input
|
||||
type="radio"
|
||||
id={`category${row.id}`}
|
||||
name="category"
|
||||
className=""
|
||||
value={row.id}
|
||||
checked={category == `${row.id}`}
|
||||
onChange={(event) => setCategory(event.target.value)}
|
||||
/>
|
||||
<label className="ml-2" htmlFor={`category${row.id}`}>
|
||||
{row.name}
|
||||
</label>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="border-b-2 border-black"></div>
|
||||
<DialogFooter>
|
||||
<Link
|
||||
href={`/auth/registration?category=${category}`}
|
||||
className="flex justify-center bg-red-500 px-4 py-1 rounded-md border border-black text-white"
|
||||
type="submit"
|
||||
>
|
||||
{t("next")}{" "}
|
||||
</Link>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
|
|
|
|||
|
|
@ -762,6 +762,11 @@
|
|||
"sent": "Sent",
|
||||
"accepted": "Accepted",
|
||||
"assignment-status-details": "Assignment Status Details",
|
||||
"unique-code": "Unique Code"
|
||||
"unique-code": "Unique Code",
|
||||
"form-media": "Form Add Media",
|
||||
"data-media": "please complete the data! ",
|
||||
"title-media-online": "Online Media Name",
|
||||
"url": "Url",
|
||||
"coverage-area": "Coverage Area"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -762,6 +762,11 @@
|
|||
"sent": "Terkirim",
|
||||
"accepted": "Diterima",
|
||||
"assignment-status-details": "Detail Status Penugasan",
|
||||
"unique-code": "Kode Unik"
|
||||
"unique-code": "Kode Unik",
|
||||
"form-media": "Form Tambah Media",
|
||||
"data-media": "Silahkan Lengkapi Data!",
|
||||
"title-media-online": "Nama Media Online",
|
||||
"url": "Url",
|
||||
"coverage-area": "Cakupan Wilayah"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue