Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import { useContext, useEffect, useState, useRef } from "react";
- import { AppContext } from "../../Context/AppContext";
- import { useNavigate, useParams, Link } from "react-router-dom";
- import { useForm, Controller } from "react-hook-form";
- import { MASTER_BOARD_NAME } from "../../constants.jsx";
- import AccessError from "../AccessError";
- import NotFound404 from "../NotFound404";
- import { getCookie } from "../../functions.jsx";
- import * as validationRules from "../../validationRulesRHF.jsx";
- import RichTextEditorRHF from "../../components/RichTextEditorRHF";
- import ErrorHead from "../../components/ErrorHead.jsx";
- import NavigationBar from "../../components/NavigationBar.jsx";
- import MegaModal from "../../components/MegaModal.jsx";
- export default function AdminUserEdit() {
- const { id } = useParams();
- const navigate = useNavigate();
- const { user, loadingUser } = useContext(AppContext);
- const [showSuccessModal, setShowSuccessModal] = useState(false);
- const [errors, setErrors] = useState({});
- const [groups, setGroups] = useState([]);
- const signatureEditorRef = useRef(null);
- const [loadingContent, setLoadingContent] = useState(true);
- // Data that is NOT being sent to the backend...
- const [tmpData, setTmpData] = useState({
- avatar: "",
- });
- const {
- register,
- control,
- handleSubmit,
- reset,
- getValues, // Querying once
- setValue,
- trigger,
- watch, // Re-querying whenever the value changes
- formState: { errors: realtimeErrors },
- } = useForm({
- defaultValues: {
- id: "",
- name: "",
- new_password: "",
- email: "",
- group: "",
- job: "",
- hobbies: "",
- location: "",
- signature: "",
- delete_avatar: "",
- },
- //mode: "onSubmit",
- mode: "onChange", // First Validation If...
- reValidateMode: "onChange", // Every Other Validation If...
- });
- //console.log(errors);
- useEffect(() => {
- const interval = setInterval(() => {
- if (window.sceditor && signatureEditorRef.current) {
- const signatureEditor = window.sceditor.instance(signatureEditorRef.current);
- const updatedSignature = signatureEditor?.val?.() || "";
- console.log(watch("signature"));
- //setValue("signature", updatedSignature);
- //trigger("signature");
- setValue("signature", updatedSignature, {
- shouldValidate: true,
- shouldDirty: true,
- shouldTouch: true,
- });
- }
- }, 100);
- // Cleanup the interval when the component unmounts
- return () => {
- clearInterval(interval);
- };
- });
- //formData = Field Values
- const onValid = async (formData, event) => {
- event.preventDefault();
- // Manually grab latest value from the editor
- const signatureEditor = window.sceditor.instance(signatureEditorRef.current);
- const updatedSignature = signatureEditor?.val?.() || "";
- const payload = {
- ...formData,
- signature: updatedSignature,
- };
- const res = await fetch(`/web/admin/users/${id}`, {
- method: "put",
- credentials: "include",
- headers: {
- "X-XSRF-TOKEN": decodeURIComponent(getCookie("XSRF-TOKEN")), // This includes the CSRF Cookie/Token (Necessary for every Request Method except GET)
- },
- //body: JSON.stringify(formData),
- body: JSON.stringify(payload),
- });
- const data = await res.json();
- console.log(data);
- if (data.errors) {
- window.scrollTo(0, 0);
- setErrors(data.errors);
- } else {
- setErrors([]);
- setShowSuccessModal(true);
- }
- };
- // formData = errors
- const onInvalid = (formData, event) => {
- console.log("Form is invalid");
- };
- useEffect(() => {
- if (user && user.group.is_admin === Number(1)) {
- document.title = `Edit User | ${MASTER_BOARD_NAME}`;
- }
- }, [user]);
- async function getGroups() {
- const res = await fetch(`/web/admin/users/groups`, {
- method: "get",
- credentials: "include",
- });
- const data = await res.json();
- if (res.ok) {
- setGroups(data.groups);
- }
- }
- useEffect(() => {
- getGroups();
- }, []);
- async function getUser() {
- const res = await fetch(`/web/admin/users/${id}`, {
- method: "get",
- credentials: "include",
- });
- const data = await res.json();
- if (res.ok) {
- reset({
- id: data.user.id,
- name: data.user.name,
- password: "",
- email: data.user.email,
- group: data.user.group.id,
- job: data.user.job,
- hobbies: data.user.hobbies,
- location: data.user.location,
- signature: data.user.signature,
- delete_avatar: 0,
- });
- setTmpData({
- avatar: data.user.avatar,
- });
- setLoadingContent(false);
- } else {
- setLoadingContent(false);
- }
- }
- useEffect(() => {
- getUser();
- }, []);
- if (!loadingUser && (!user || user.group.is_admin != Number(1))) {
- return <AccessError />;
- }
- //if (!loadingContent && !formData.id) {
- if (!loadingContent && !watch("id")) {
- return <NotFound404 />;
- }
- return (
- <>
- <div className="container py-4">
- {/* Breadcrumb Navigation */}
- <NavigationBar
- breadcrumbs={{
- items: [
- { item_name: "Home", item_url: "/", item_loaded: true },
- {
- item_name: "Admin Dashboard",
- item_url: `/admin/dashboard`,
- item_loaded: true,
- },
- {
- item_name: "Manage Users",
- item_url: `/admin/user/list`,
- item_loaded: true,
- },
- { item_name: "Edit User", item_loaded: true, item_active: true },
- ],
- }}
- />
- {/* Error Box */}
- <ErrorHead errors={errors} />
- {!loadingUser && !loadingContent ? (
- <>
- <div className="card shadow-sm">
- <div className="card-header bg-secondary bg-opacity-25 fw-bold">
- Edit User "{watch("name")}"
- </div>
- <div className="card-body">
- <form onSubmit={handleSubmit(onValid, onInvalid)}>
- {/* Required Fields Card */}
- <div className="card mb-3">
- <div className="card-header bg-light fw-semibold">Required Information</div>
- <div className="card-body">
- {/* Username */}
- <div className="mb-3">
- <label htmlFor="name" className="form-label">
- Username
- </label>
- <input
- className="form-control"
- type="text"
- placeholder="Enter username"
- id="name"
- {...register("name", validationRules.username)}
- />
- {realtimeErrors.name?.message ? (
- <p className="text-danger mt-2">{realtimeErrors.name.message}</p>
- ) : null}
- </div>
- {/* New Password */}
- <div className="mb-3">
- <label htmlFor="new_password" className="form-label">
- Password
- </label>
- <input
- className="form-control"
- type="password"
- placeholder="Enter new password (Optional)"
- id="new_password"
- {...register("new_password", validationRules.new_password)}
- />
- {realtimeErrors.new_password?.message ? (
- <p className="text-danger mt-2">{realtimeErrors.new_password.message}</p>
- ) : null}
- </div>
- {/* Email */}
- <div className="mb-3">
- <label htmlFor="email" className="form-label">
- Email
- </label>
- <input
- className="form-control"
- type="text"
- placeholder="Enter email"
- id="email"
- {...register("email", validationRules.email)}
- />
- {realtimeErrors.email?.message ? (
- <p className="text-danger mt-2">{realtimeErrors.email.message}</p>
- ) : null}
- </div>
- {/* Usergroup */}
- <div className="mb-3">
- <label htmlFor="group" className="form-label">
- Usergroup
- </label>
- <select
- className="form-select"
- id="group"
- value={getValues("group") || ""}
- {...register("group", validationRules.usergroup)}
- >
- <option value="">Select a usergroup</option>
- {groups.map((group) => (
- <option key={group.id} value={group.id}>
- {group.name}
- </option>
- ))}
- </select>
- {realtimeErrors.group?.message ? (
- <p className="text-danger mt-2">{realtimeErrors.group.message}</p>
- ) : null}
- </div>
- </div>
- </div>
- {/* Optional Fields Card */}
- <div className="card mb-3">
- <div className="card-header bg-light fw-semibold">Optional Information</div>
- <div className="card-body">
- {/* Job */}
- <div className="mb-3">
- <label htmlFor="job" className="form-label">
- Job
- </label>
- <input
- className="form-control"
- type="text"
- placeholder="Enter job title"
- id="job"
- {...register(
- "job",
- validationRules.genericOptionalMaxLengthField("Job", 100)
- )}
- />
- {realtimeErrors.job?.message ? (
- <p className="text-danger mt-2">{realtimeErrors.job.message}</p>
- ) : null}
- </div>
- {/* Hobbies */}
- <div className="mb-3">
- <label htmlFor="hobbies" className="form-label">
- Hobbies
- </label>
- <input
- className="form-control"
- type="text"
- placeholder="Enter hobbies"
- id="hobbies"
- {...register(
- "hobbies",
- validationRules.genericOptionalMaxLengthField("Hobbies", 100)
- )}
- />
- {realtimeErrors.hobbies?.message ? (
- <p className="text-danger mt-2">{realtimeErrors.hobbies.message}</p>
- ) : null}
- </div>
- {/* Location */}
- <div className="mb-3">
- <label htmlFor="location" className="form-label">
- Location
- </label>
- <input
- className="form-control"
- type="text"
- placeholder="Enter location"
- id="location"
- {...register(
- "location",
- validationRules.genericOptionalMaxLengthField("Location", 100)
- )}
- />
- {realtimeErrors.location?.message ? (
- <p className="text-danger mt-2">{realtimeErrors.location.message}</p>
- ) : null}
- </div>
- {/* Signature */}
- {/*
- <div className="mb-3">
- <label htmlFor="signature" className="form-label">
- Signature
- </label>
- <RichTextEditorRHF ref={signatureEditorRef} value={formData.signature} />
- </div>
- */}
- <div className="mb-3">
- <label htmlFor="signature" className="form-label">
- Signature
- </label>
- <RichTextEditorRHF
- ref={signatureEditorRef}
- value={watch("signature")}
- rhfRegister={register}
- rhfFieldName="signature"
- rhfValidationRules={validationRules.email}
- />
- {realtimeErrors.signature?.message ? (
- <p className="text-danger mt-2">{realtimeErrors.signature.message}</p>
- ) : null}
- </div>
- {/* Avatar */}
- {tmpData.avatar && (
- <div className="mb-3">
- <label htmlFor="signature" className="form-label">
- Avatar
- </label>
- <div>
- <img
- src={
- tmpData.avatar
- ? `${tmpData.avatar}?v=${Date.now()}`
- : "/no-avatar.png"
- }
- alt="avatar"
- className="rounded-circle mb-2"
- style={{ width: "100px", height: "100px" }}
- />
- </div>
- <div className="form-check">
- <input
- className="form-check-input"
- type="checkbox"
- id="delete_avatar"
- {...register("delete_avatar", {
- setValueAs: (value) => (value ? 1 : 0), // Convert true/false to 1/0
- })}
- />
- <label className="form-check-label" htmlFor="delete_avatar">
- Delete Avatar?
- </label>
- </div>
- </div>
- )}
- </div>
- </div>
- {/* Actions */}
- <div className="d-flex justify-content-between">
- <Link to="/admin/user/list" className="btn btn-secondary">
- Cancel
- </Link>
- <button type="submit" className="btn btn-success">
- Save
- </button>
- </div>
- </form>
- </div>
- </div>
- </>
- ) : (
- <>
- <div className="card p-3">Loading...</div>
- </>
- )}
- </div>
- {/* Success Modal */}
- <MegaModal
- data={{
- modal_show: showSuccessModal,
- modal_type: "generic",
- modal_title: "Success",
- modal_title_classes: "bg-success text-white",
- modal_text: `User <strong>${watch("name")} </strong> has been successfully updated.`,
- modal_show_no_undo_warning: false,
- buttons: [
- {
- title: "Go to Userlist",
- classes: "btn btn-primary",
- onclick: () => {
- navigate("/admin/user/list");
- setShowSuccessModal(false);
- },
- },
- {
- title: "Keep Editing",
- classes: "btn btn-primary",
- onclick: () => {
- getUser();
- setShowSuccessModal(false);
- },
- },
- ],
- }}
- />
- </>
- );
- }
Advertisement
Add Comment
Please, Sign In to add comment