feat:scheduled create article
This commit is contained in:
parent
ec2e0ef1b8
commit
f2e3d7f731
|
|
@ -6,18 +6,21 @@ import Cookies from "js-cookie";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
|
|
||||||
export default function AuthPage() {
|
export default function AuthPage() {
|
||||||
const isAuthenticated = Cookies.get("is_authenticated") || "false";
|
// const isAuthenticated = Cookies.get("is_authenticated") || "false";
|
||||||
|
|
||||||
console.log("isAuthenticated : ", isAuthenticated);
|
// console.log("isAuthenticated : ", isAuthenticated);
|
||||||
|
|
||||||
const [hasMounted, setHasMounted] = useState(false);
|
// const [hasMounted, setHasMounted] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
setHasMounted(true);
|
// setHasMounted(true);
|
||||||
}, []);
|
// }, []);
|
||||||
|
|
||||||
// Render
|
// // Render
|
||||||
if (!hasMounted) return null;
|
// if (!hasMounted) return null;
|
||||||
|
|
||||||
return isAuthenticated == "true" ? <Login /> : <QudoLogin />;
|
return <Login />;
|
||||||
|
|
||||||
|
// isAuthenticated == "true" ?
|
||||||
|
// : <QudoLogin />;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,12 @@
|
||||||
"use client";
|
"use client";
|
||||||
import { FormEvent, Fragment, useEffect, useRef, useState } from "react";
|
import {
|
||||||
|
FormEvent,
|
||||||
|
Fragment,
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from "react";
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
|
@ -24,9 +31,15 @@ import makeAnimated from "react-select/animated";
|
||||||
import {
|
import {
|
||||||
Checkbox,
|
Checkbox,
|
||||||
Chip,
|
Chip,
|
||||||
|
Modal,
|
||||||
|
ModalBody,
|
||||||
|
ModalContent,
|
||||||
|
ModalFooter,
|
||||||
|
ModalHeader,
|
||||||
Select,
|
Select,
|
||||||
SelectItem,
|
SelectItem,
|
||||||
SelectSection,
|
SelectSection,
|
||||||
|
useDisclosure,
|
||||||
} from "@nextui-org/react";
|
} from "@nextui-org/react";
|
||||||
import GenerateSingleArticleForm from "./generate-ai-single-form";
|
import GenerateSingleArticleForm from "./generate-ai-single-form";
|
||||||
import { htmlToString } from "@/utils/global";
|
import { htmlToString } from "@/utils/global";
|
||||||
|
|
@ -39,6 +52,7 @@ import {
|
||||||
updateManualArticle,
|
updateManualArticle,
|
||||||
} from "@/service/generate-article";
|
} from "@/service/generate-article";
|
||||||
import GenerateContentRewriteForm from "./generate-ai-content-rewrite-form";
|
import GenerateContentRewriteForm from "./generate-ai-content-rewrite-form";
|
||||||
|
import Datepicker from "react-tailwindcss-datepicker";
|
||||||
|
|
||||||
const CustomEditor = dynamic(
|
const CustomEditor = dynamic(
|
||||||
() => {
|
() => {
|
||||||
|
|
@ -92,6 +106,8 @@ const createArticleSchema = z.object({
|
||||||
});
|
});
|
||||||
|
|
||||||
export default function CreateArticleForm() {
|
export default function CreateArticleForm() {
|
||||||
|
const { isOpen, onOpen, onOpenChange } = useDisclosure();
|
||||||
|
|
||||||
const animatedComponents = makeAnimated();
|
const animatedComponents = makeAnimated();
|
||||||
const MySwal = withReactContent(Swal);
|
const MySwal = withReactContent(Swal);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -108,7 +124,16 @@ export default function CreateArticleForm() {
|
||||||
const [filesValidation, setFileValidation] = useState("");
|
const [filesValidation, setFileValidation] = useState("");
|
||||||
const [diseData, setDiseData] = useState<DiseData>();
|
const [diseData, setDiseData] = useState<DiseData>();
|
||||||
const [selectedWritingType, setSelectedWritingType] = useState("single");
|
const [selectedWritingType, setSelectedWritingType] = useState("single");
|
||||||
const [status, setStatus] = useState<"publish" | "draft">("publish");
|
const [status, setStatus] = useState<"publish" | "draft" | "scheduled">(
|
||||||
|
"publish"
|
||||||
|
);
|
||||||
|
const [isScheduled, setIsScheduled] = useState(false);
|
||||||
|
const [timeValue, setTimeValue] = useState("");
|
||||||
|
|
||||||
|
const [startDateValue, setStartDateValue] = useState({
|
||||||
|
startDate: null,
|
||||||
|
endDate: null,
|
||||||
|
});
|
||||||
|
|
||||||
const { getRootProps, getInputProps } = useDropzone({
|
const { getRootProps, getInputProps } = useDropzone({
|
||||||
onDrop: (acceptedFiles) => {
|
onDrop: (acceptedFiles) => {
|
||||||
|
|
@ -132,7 +157,7 @@ export default function CreateArticleForm() {
|
||||||
register,
|
register,
|
||||||
control,
|
control,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
formState: { errors },
|
formState: { errors, isValid },
|
||||||
setValue,
|
setValue,
|
||||||
getValues,
|
getValues,
|
||||||
watch,
|
watch,
|
||||||
|
|
@ -177,8 +202,7 @@ export default function CreateArticleForm() {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setThumbnailValidation("");
|
setThumbnailValidation("");
|
||||||
setFileValidation("Required");
|
setFileValidation("");
|
||||||
|
|
||||||
MySwal.fire({
|
MySwal.fire({
|
||||||
title: "Simpan Data",
|
title: "Simpan Data",
|
||||||
text: "",
|
text: "",
|
||||||
|
|
@ -426,14 +450,6 @@ export default function CreateArticleForm() {
|
||||||
setValue("tags", uniqueArray as [string, ...string[]]);
|
setValue("tags", uniqueArray as [string, ...string[]]);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
console.log("seklec", selectedMainImage);
|
|
||||||
console.log("seklssssec", files);
|
|
||||||
if (selectedMainImage) {
|
|
||||||
console.log("filll", files[selectedMainImage]);
|
|
||||||
}
|
|
||||||
}, [selectedMainImage]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
className="flex flex-col lg:flex-row gap-8 text-black"
|
className="flex flex-col lg:flex-row gap-8 text-black"
|
||||||
|
|
@ -750,12 +766,59 @@ export default function CreateArticleForm() {
|
||||||
{errors?.tags && (
|
{errors?.tags && (
|
||||||
<p className="text-red-400 text-sm mb-3">{errors.tags?.message}</p>
|
<p className="text-red-400 text-sm mb-3">{errors.tags?.message}</p>
|
||||||
)}
|
)}
|
||||||
|
<div className="flex flex-col gap-2 mt-3">
|
||||||
|
<Switch isSelected={isScheduled} onValueChange={setIsScheduled}>
|
||||||
|
Publish dengan Jadwal
|
||||||
|
</Switch>
|
||||||
|
{isScheduled && (
|
||||||
|
<div className="flex flex-col lg:flex-row gap-3">
|
||||||
|
<div className="w-full lg:w-[140px] flex flex-col gal-2 ">
|
||||||
|
<p className="text-sm">Tanggal</p>
|
||||||
|
<Datepicker
|
||||||
|
value={startDateValue}
|
||||||
|
displayFormat="DD/MM/YYYY"
|
||||||
|
popoverDirection="down"
|
||||||
|
asSingle={true}
|
||||||
|
useRange={false}
|
||||||
|
onChange={(e: any) => setStartDateValue(e)}
|
||||||
|
inputClassName="z-50 w-full text-xs lg:text-sm bg-white dark bg-black border-1 border-gray-200 px-2 py-[6px] rounded-sm lg:rounded-lg h-[30px] lg:h-[40px] text-gray-600 dark:text-gray-300"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="w-[140px] flex flex-col gal-2 ">
|
||||||
|
<p className="text-sm">Waktu</p>
|
||||||
|
<Input
|
||||||
|
type="time"
|
||||||
|
value={timeValue}
|
||||||
|
onValueChange={setTimeValue}
|
||||||
|
variant="bordered"
|
||||||
|
className="w-full"
|
||||||
|
classNames={{
|
||||||
|
input: "h-[30px]",
|
||||||
|
mainWrapper: ["bg-white !h-[30px] lg:h-[40px]"],
|
||||||
|
innerWrapper: "!h-[30px] lg:h-[40px]",
|
||||||
|
inputWrapper: [
|
||||||
|
"border-1 rounded-lg !h-[30px] lg:h-[40px]",
|
||||||
|
"dark:group-data-[focused=false]:bg-transparent !border-1 dark:!border-gray-400",
|
||||||
|
],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-row justify-end gap-3">
|
<div className="flex flex-row justify-end gap-3">
|
||||||
<Button
|
<Button
|
||||||
color="primary"
|
color="primary"
|
||||||
type="submit"
|
type="submit"
|
||||||
onClick={() => setStatus("publish")}
|
isDisabled={
|
||||||
|
(isScheduled && startDateValue.startDate == null) ||
|
||||||
|
(isScheduled && timeValue == "")
|
||||||
|
}
|
||||||
|
onClick={() =>
|
||||||
|
isScheduled ? setStatus("scheduled") : setStatus("publish")
|
||||||
|
}
|
||||||
>
|
>
|
||||||
Publish
|
Publish
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -68,11 +68,11 @@ export default function NavbarHumas(props: { size: string }) {
|
||||||
const language = storedLanguage((state) => state.locale);
|
const language = storedLanguage((state) => state.locale);
|
||||||
const setLanguage = storedLanguage((state) => state.setLocale);
|
const setLanguage = storedLanguage((state) => state.setLocale);
|
||||||
|
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
if (!isAuthenticated) {
|
// if (!isAuthenticated) {
|
||||||
onLogout();
|
// onLogout();
|
||||||
}
|
// }
|
||||||
}, [token]);
|
// }, [token]);
|
||||||
|
|
||||||
const onLogout = () => {
|
const onLogout = () => {
|
||||||
Object.keys(Cookies.get()).forEach((cookieName) => {
|
Object.keys(Cookies.get()).forEach((cookieName) => {
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,15 @@ const dummyTopPages = [
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const dummyViz = {
|
||||||
|
todayPost: 10,
|
||||||
|
weeklyPost: 56,
|
||||||
|
totalPost: 223,
|
||||||
|
totalView: 422,
|
||||||
|
totalShare: 126,
|
||||||
|
totalComment: 67,
|
||||||
|
};
|
||||||
|
|
||||||
const dummyPostCount = [
|
const dummyPostCount = [
|
||||||
{ id: 1, name: "Polda Sumatera Utara", count: 132 },
|
{ id: 1, name: "Polda Sumatera Utara", count: 132 },
|
||||||
{ id: 2, name: "Polda Metro Jaya", count: 128 },
|
{ id: 2, name: "Polda Metro Jaya", count: 128 },
|
||||||
|
|
@ -210,10 +219,12 @@ export default function DashboardContainer() {
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row gap-5">
|
<div className="flex flex-row gap-5">
|
||||||
<p className="text-lg font-semibold">
|
<p className="text-lg font-semibold">
|
||||||
4 Post <span className="text-sm font-normal">Hari ini</span>
|
{dummyViz.todayPost} Post{" "}
|
||||||
|
<span className="text-sm font-normal">Hari ini</span>
|
||||||
</p>
|
</p>
|
||||||
<p className="text-lg font-semibold">
|
<p className="text-lg font-semibold">
|
||||||
12 Post <span className="text-sm font-normal">Minggu ini</span>
|
{dummyViz.weeklyPost} Post{" "}
|
||||||
|
<span className="text-sm font-normal">Minggu ini</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -223,28 +234,28 @@ export default function DashboardContainer() {
|
||||||
<DashboardSpeecIcon />
|
<DashboardSpeecIcon />
|
||||||
</div>
|
</div>
|
||||||
<div className="">Total post</div>
|
<div className="">Total post</div>
|
||||||
<div className="font-semibold text-lg">121</div>
|
<div className="font-semibold text-lg">{dummyViz.totalPost}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full lg:w-[15%] h-[160px] shadow-md bg-white dark:bg-[#18181b] flex flex-col justify-center items-center rounded-lg">
|
<div className="w-full lg:w-[15%] h-[160px] shadow-md bg-white dark:bg-[#18181b] flex flex-col justify-center items-center rounded-lg">
|
||||||
<div className="h-1/2 flex items-center justify-center">
|
<div className="h-1/2 flex items-center justify-center">
|
||||||
<DashboardConnectIcon />
|
<DashboardConnectIcon />
|
||||||
</div>
|
</div>
|
||||||
<div className="">Total views</div>
|
<div className="">Total views</div>
|
||||||
<div className="font-semibold text-lg">154</div>
|
<div className="font-semibold text-lg">{dummyViz.totalView}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full lg:w-[15%] h-[160px] shadow-md bg-white dark:bg-[#18181b] flex flex-col justify-center items-center rounded-lg">
|
<div className="w-full lg:w-[15%] h-[160px] shadow-md bg-white dark:bg-[#18181b] flex flex-col justify-center items-center rounded-lg">
|
||||||
<div className="h-1/2 flex items-center justify-center">
|
<div className="h-1/2 flex items-center justify-center">
|
||||||
<DashboardShareIcon />
|
<DashboardShareIcon />
|
||||||
</div>
|
</div>
|
||||||
<div className="">Total share</div>
|
<div className="">Total share</div>
|
||||||
<div className="font-semibold text-lg">154</div>
|
<div className="font-semibold text-lg">{dummyViz.totalShare}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full lg:w-[15%] h-[160px] shadow-md bg-white dark:bg-[#18181b] flex flex-col justify-center items-center rounded-lg">
|
<div className="w-full lg:w-[15%] h-[160px] shadow-md bg-white dark:bg-[#18181b] flex flex-col justify-center items-center rounded-lg">
|
||||||
<div className="h-1/2 flex items-center justify-center">
|
<div className="h-1/2 flex items-center justify-center">
|
||||||
<DashboardCommentIcon size={50} />
|
<DashboardCommentIcon size={50} />
|
||||||
</div>
|
</div>
|
||||||
<div className="">Total comment</div>
|
<div className="">Total comment</div>
|
||||||
<div className="font-semibold text-lg">530</div>
|
<div className="font-semibold text-lg">{dummyViz.totalComment}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full flex flex-col lg:flex-row gap-6 justify-center ">
|
<div className="w-full flex flex-col lg:flex-row gap-6 justify-center ">
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue