411 lines
19 KiB
JavaScript
411 lines
19 KiB
JavaScript
// import axios from "axios";
|
||
import React, { use, useEffect, useState } from "react";
|
||
import toast from "react-hot-toast";
|
||
import { useRouter } from "next/router";
|
||
import Link from "next/link";
|
||
import axiosInstance from '../../src/axiosSecure';
|
||
//import { getDate } from "date-fns";
|
||
|
||
import PwaManager from "../PwaManager";
|
||
import common from "../../src/helpers/common";
|
||
import ProtectedRoute from '../../components/protectedRoute';
|
||
import { monthNamesBG, GetTimeFormat, GetDateFormat } from "../../src/helpers/const"
|
||
import PublisherSearchBox from './PublisherSearchBox';
|
||
import AvailabilityList from "../availability/AvailabilityList";
|
||
import ShiftsList from "../publisher/ShiftsList.tsx";
|
||
import ConfirmationModal from "../ConfirmationModal";
|
||
import { UserRole } from "@prisma/client";
|
||
import { useSession } from "next-auth/react"
|
||
|
||
// import { Tabs, List } from 'tw-elements'
|
||
|
||
Array.prototype.groupBy = function (prop) {
|
||
return this.reduce(function (groups, item) {
|
||
const val = item[prop]
|
||
groups[val] = groups[val] || []
|
||
groups[val].push(item)
|
||
return groups
|
||
}, {})
|
||
}
|
||
|
||
export default function PublisherForm({ item, me }) {
|
||
const router = useRouter();
|
||
const { data: session } = useSession()
|
||
const [congregations, setCongregations] = useState([]);
|
||
|
||
const urls = {
|
||
apiUrl: "/api/data/publishers/",
|
||
congregationsUrl: "/api/data/congregations",
|
||
indexUrl: session?.user?.role == UserRole.ADMIN ? "/cart/publishers" : "/dash"
|
||
}
|
||
console.log("urls.indexUrl: " + urls.indexUrl);
|
||
const [helpers, setHelper] = useState(null);
|
||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||
|
||
const fetchModules = async () => {
|
||
const h = (await import("../../src/helpers/const.js")).default;
|
||
//console.log("fetchModules: " + JSON.stringify(h));
|
||
setHelper(h);
|
||
|
||
const response = await axiosInstance.get(urls.congregationsUrl);
|
||
setCongregations(response.data);
|
||
}
|
||
useEffect(() => {
|
||
fetchModules();
|
||
}, []);
|
||
|
||
const [publisher, set] = useState(item || {
|
||
isActive: true,
|
||
});
|
||
|
||
const handleChange = ({ target }) => {
|
||
if (target.type === "checkbox") {
|
||
set({ ...publisher, [target.name]: target.checked });
|
||
} else if (target.type === "number") {
|
||
set({ ...publisher, [target.name]: parseInt(target.value) });
|
||
} else {
|
||
set({ ...publisher, [target.name]: target.value });
|
||
}
|
||
if (item?.firstName) {
|
||
publisher.isMale = item.firstName && item.firstName.endsWith('а') ? false : true;
|
||
}
|
||
}
|
||
|
||
|
||
const handleParentSelection = (head) => {
|
||
//setSelectedParent(parent);
|
||
// Update the publisher state with the selected publisher's ID
|
||
console.log("handleParentSelection: " + JSON.stringify(head));
|
||
set({ ...publisher, familyHeadId: head.id });
|
||
// Create a new object excluding the familyHeadId property
|
||
|
||
};
|
||
|
||
const handleSubmit = async (e) => {
|
||
router.query.id = router.query.id || "";
|
||
console.log("handleSubmit: " + JSON.stringify(publisher));
|
||
console.log("urls.apiUrl + router.query.id: " + urls.apiUrl + router.query.id)
|
||
e.preventDefault();
|
||
//remove availabilities, assignments from publisher
|
||
publisher.availabilities = undefined;
|
||
publisher.assignments = undefined;
|
||
|
||
let { familyHeadId, userId, congregationId, ...rest } = publisher;
|
||
// Set the familyHead relation based on the selected head
|
||
const familyHeadRelation = familyHeadId ? { connect: { id: familyHeadId } } : null;
|
||
const userRel = userId ? { connect: { id: userId } } : null;
|
||
const congregationRel = congregationId ? { connect: { id: parseInt(congregationId) } } : null;
|
||
// Return the new state without familyHeadId and with the correct familyHead relation
|
||
rest = {
|
||
...rest,
|
||
...(familyHeadRelation ? { familyHead: familyHeadRelation } : {}),
|
||
...(userRel ? { user: userRel } : {}),
|
||
...(congregationRel ? { congregation: congregationRel } : {}),
|
||
};
|
||
|
||
try {
|
||
if (router.query?.id) {
|
||
await axiosInstance.put(urls.apiUrl + router.query.id, {
|
||
...rest,
|
||
});
|
||
toast.success("Task Updated", {
|
||
position: "bottom-center",
|
||
});
|
||
} else {
|
||
await axiosInstance.post(urls.apiUrl, rest);
|
||
toast.success("Task Saved", {
|
||
position: "bottom-center",
|
||
});
|
||
}
|
||
router.push(urls.indexUrl);
|
||
} catch (error) {
|
||
console.log(JSON.stringify(error));
|
||
//toast.error(error.response.data.message);
|
||
}
|
||
};
|
||
|
||
const handleDelete = async (e) => {
|
||
e.preventDefault();
|
||
try {
|
||
//console.log("deleting publisher id = ", router.query.id, "; url=" + urls.apiUrl + router.query.id);
|
||
await axiosInstance.delete(urls.apiUrl + router.query.id);
|
||
toast.success("Записът изтрит", {
|
||
position: "bottom-center",
|
||
});
|
||
router.push(urls.indexUrl);
|
||
} catch (error) {
|
||
console.log(JSON.stringify(error));
|
||
toast.error(error.response.data.message);
|
||
}
|
||
};
|
||
|
||
|
||
|
||
let formTitle;
|
||
me = common.parseBool(me);
|
||
if (me) {
|
||
formTitle = "Моят профил / Настройки";
|
||
} else if (router.query?.id) {
|
||
formTitle = "Редактирай вестител"; // "Edit Publisher"
|
||
} else {
|
||
formTitle = "Създай вестител"; // "Create Publisher"
|
||
}
|
||
return (
|
||
<>
|
||
<div className="flex flex-col">
|
||
<h3 className="text-2xl font-semibold mt-6 mb-4">{formTitle}</h3>
|
||
<div className="h-4"></div>
|
||
<div className="flex flex-row">
|
||
|
||
<form className="form"
|
||
onSubmit={handleSubmit}>
|
||
<div className="mb-4">
|
||
<label className="label" htmlFor="firstName">Име</label>
|
||
<input type="text" id="firstName" name="firstName" value={publisher.firstName} onChange={handleChange} className="textbox" placeholder="First Name" autoFocus />
|
||
</div>
|
||
<div className="mb-4">
|
||
<label className="label" htmlFor="lastName">Фамилия</label>
|
||
<input type="text" id="lastName" name="lastName" value={publisher.lastName} onChange={handleChange} className="textbox" placeholder="Last Name" autoFocus />
|
||
<ProtectedRoute allowedRoles={[UserRole.ADMIN]} deniedMessage=" ">
|
||
|
||
<div className="border border-blue-500 border-solid p-2">
|
||
<div className="form-check">
|
||
<input className="checkbox" type="checkbox" value={publisher.isNameForeign} id="isNameForeign" name="isNameForeign" onChange={handleChange} checked={publisher.isNameForeign} autoComplete="off" />
|
||
<label className="label" htmlFor="isNameForeign">
|
||
Чуждестранна фамилия</label>
|
||
</div>
|
||
</div>
|
||
</ProtectedRoute>
|
||
</div>
|
||
{/* //desiredShiftsPerMonth */}
|
||
<div className="mb-4">
|
||
<label className="label" htmlFor="desiredShiftsPerMonth">Желани смeни на месец</label>
|
||
<input type="number" id="desiredShiftsPerMonth" name="desiredShiftsPerMonth" value={publisher.desiredShiftsPerMonth} onChange={handleChange} className="textbox" placeholder="desiredShiftsPerMonth" autoFocus />
|
||
</div> <div className="mb-4">
|
||
<label className="label" htmlFor="email">Имейл</label>
|
||
<ProtectedRoute allowedRoles={[UserRole.ADMIN]} deniedMessage={publisher.email} className="">
|
||
<div className="border border-blue-500 border-solid p-2">
|
||
<input type="text" id="email" name="email" value={publisher.email} onChange={handleChange} className="textbox" placeholder="Email" autoFocus />
|
||
</div>
|
||
</ProtectedRoute>
|
||
</div>
|
||
<div className="mb-4">
|
||
<label className="label" htmlFor="phone">Телефон</label>
|
||
<input type="text" id="phone" name="phone" value={publisher.phone} onChange={handleChange} className="textbox" placeholder="Phone" autoFocus />
|
||
</div>
|
||
<div className="mb-4">
|
||
<label className="label" htmlFor="familyHeadId">
|
||
Семейство (избери главата на семейството)
|
||
</label>
|
||
<PublisherSearchBox id="familyHeadId" selectedId={publisher.familyHeadId} onChange={handleParentSelection} />
|
||
</div>
|
||
<div className="mb-4">
|
||
<div className="flex items-center space-x-4">
|
||
<div className="form-check">
|
||
<input className="radio" type="radio" id="male" name="isMale"
|
||
onChange={() => handleChange({ target: { name: "isMale", value: true } })}
|
||
checked={publisher.isMale}
|
||
/>
|
||
<label className="label" htmlFor="male">
|
||
Мъж
|
||
</label>
|
||
</div>
|
||
<div className="form-check">
|
||
<input className="radio" type="radio" id="female" name="isMale"
|
||
onChange={() => handleChange({ target: { name: "isMale", value: false } })}
|
||
checked={!publisher.isMale}
|
||
/>
|
||
<label className="label" htmlFor="female">
|
||
Жена
|
||
</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{/* language preference */}
|
||
<div className="mb-4">
|
||
<label className="label" htmlFor="locale">Език (в разработка)</label>
|
||
<select id="locale" name="locale" value={publisher.locale} onChange={handleChange} className="select textbox" placeholder="Език" autoFocus >
|
||
<option value="bg" >Български</option>
|
||
<option value="en">English</option>
|
||
<option value="ru">Руски</option>
|
||
</select>
|
||
</div>
|
||
<div className="mb-4">
|
||
<label className="label" htmlFor="town">Град</label>
|
||
<input type="text" id="town" name="town" value={publisher.town} onChange={handleChange} className="textbox" placeholder="Град" autoFocus />
|
||
</div>
|
||
<div className="mb-4">
|
||
<label className="label" htmlFor="congregationId">Сбор</label>
|
||
<select id="congregationId" name="congregationId" value={publisher.congregationId} onChange={handleChange} className="select textbox" placeholder="Община" autoFocus >
|
||
<option value="">Избери сбор</option>
|
||
{congregations.map((congregation) => (
|
||
<option key={congregation.id} value={congregation.id}>
|
||
{congregation.name}
|
||
</option>
|
||
))}
|
||
</select>
|
||
</div>
|
||
|
||
|
||
|
||
{/* notifications */}
|
||
<div className="mb-6 p-4 border border-gray-300 rounded-lg">
|
||
<fieldset>
|
||
<legend className="text-lg font-medium mb-2">Известия</legend>
|
||
|
||
{/* Email notifications group */}
|
||
<div className="mb-4">
|
||
<h3 className="text-md font-semibold mb-2">Известия по имейл</h3>
|
||
<div className="space-y-4">
|
||
<div className="form-check">
|
||
<input
|
||
className="checkbox cursor-not-allowed opacity-50"
|
||
type="checkbox"
|
||
id="isSubscribedToCoverMeMandatory"
|
||
name="isSubscribedToCoverMeMandatory"
|
||
onChange={handleChange} // This will not fire due to being disabled, but kept for consistency
|
||
checked={true} // Always checked
|
||
disabled={true} // User cannot change this field
|
||
autoComplete="off" />
|
||
<label className="label cursor-not-allowed opacity-50" htmlFor="isSubscribedToCoverMeMandatory">
|
||
Имейли за заместване които отговарят на моите предпочитания
|
||
</label>
|
||
</div>
|
||
<div className="form-check">
|
||
<input
|
||
className="checkbox"
|
||
type="checkbox"
|
||
id="isSubscribedToCoverMe"
|
||
name="isSubscribedToCoverMe"
|
||
onChange={handleChange}
|
||
checked={publisher.isSubscribedToCoverMe}
|
||
autoComplete="off" />
|
||
<label className="label" htmlFor="isSubscribedToCoverMe">
|
||
Всички заявки за заместване
|
||
</label>
|
||
</div>
|
||
<div className="form-check">
|
||
<input
|
||
className="checkbox"
|
||
type="checkbox"
|
||
id="isSubscribedToReminders"
|
||
name="isSubscribedToReminders"
|
||
onChange={handleChange}
|
||
checked={publisher.isSubscribedToReminders}
|
||
autoComplete="off" />
|
||
<label className="label" htmlFor="isSubscribedToReminders">
|
||
Други напомняния
|
||
</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* In-App notifications group */}
|
||
<div className="mb-4">
|
||
<h3 className="text-md font-semibold mb-2">Известия в приложението</h3>
|
||
<PwaManager userId={publisher.userId || session.user.id} />
|
||
|
||
</div>
|
||
</fieldset>
|
||
</div>
|
||
|
||
{/* button to install PWA */}
|
||
{/* <div className="mb-4">
|
||
<button className="button bg-blue-500 hover:bg-blue-700 focus:outline-none focus:shadow-outline" type="button" onClick={() => window.installPWA()}>
|
||
Инсталирай приложението
|
||
</div> */}
|
||
|
||
|
||
{/* ADMINISTRATORS ONLY */}
|
||
<ProtectedRoute allowedRoles={[UserRole.ADMIN, UserRole.POWERUSER]} deniedMessage=" " className="">
|
||
<div className="border border-blue-500 border-solid p-2">
|
||
{/* prompt to install PWA */}
|
||
<div className="mb-4">
|
||
<label className="label" htmlFor="type">Тип</label>
|
||
<select id="type" name="type" value={publisher.type} onChange={handleChange} className="textbox" placeholder="Type" autoFocus >
|
||
<option value="Publisher">Вестител</option>
|
||
<option value="Bethelite">Бетелит</option>
|
||
<option value="RegularPioneer">Редовен Пионер</option>
|
||
<option value="SpecialPioneer_Missionary">Специален Пионер/Мисионер</option>
|
||
{/* <option value="Missionary">Мисионер</option>
|
||
<option value="CircuitOverseer">Пътуваща служба</option> */}
|
||
</select>
|
||
</div>
|
||
<div className="mb-4">
|
||
<label className="label" htmlFor="comments">Коментари</label>
|
||
<input type="text" id="comments" name="comments" value={publisher.comments} onChange={handleChange} className="textbox" placeholder="Коментари" autoFocus />
|
||
</div>
|
||
<div className="mb-4">
|
||
<label className="label" htmlFor="age">Възраст</label>
|
||
<input type="number" id="age" name="age" value={publisher.age} onChange={handleChange} className="textbox" placeholder="Age" autoFocus />
|
||
</div>
|
||
<div className="mb-4">
|
||
<div className="form-check">
|
||
|
||
<ProtectedRoute allowedRoles={[UserRole.ADMIN]} deniedMessage=" ">
|
||
<input className="checkbox disabled" type="checkbox" id="isImported" name="isImported" onChange={handleChange} checked={publisher.isImported} autoComplete="off" />
|
||
<label className="label " htmlFor="isImported">Импортиран от график</label>
|
||
</ProtectedRoute>
|
||
<input className="checkbox" type="checkbox" id="isActive" name="isActive" onChange={handleChange} checked={publisher.isActive} autoComplete="off" />
|
||
<label className="label" htmlFor="isActive">Активен</label>
|
||
<input className="checkbox" type="checkbox" id="isTrained" name="isTrained" onChange={handleChange} checked={publisher.isTrained} autoComplete="off" />
|
||
<label className="label" htmlFor="isTrained">Получил обучение</label>
|
||
|
||
</div>
|
||
</div>
|
||
<div className="mb-4">
|
||
<label className="label" htmlFor="role">Роля Потребител</label>
|
||
<select name="role" id="role" className="select" value={publisher.role} onChange={handleChange} >
|
||
{/* <option value='${UserRole.USER}'>Потребител</option> */}
|
||
<option value={`${UserRole.USER}`}>Потребител</option>
|
||
<option value={`${UserRole.EXTERNAL}`}>Външен</option>
|
||
<option value={`${UserRole.POWERUSER}`}>Организатор</option>
|
||
<ProtectedRoute allowedRoles={[UserRole.ADMIN]} deniedMessage=" ">
|
||
<option value={`${UserRole.ADMIN}`}>Администратор</option>
|
||
</ProtectedRoute>
|
||
{/* Add other roles as needed */}
|
||
</select>
|
||
</div>
|
||
</div>
|
||
</ProtectedRoute>
|
||
{/* ---------------------------- Actions --------------------------------- */}
|
||
<div className="panel-actions">
|
||
<Link href={urls.indexUrl} className="action-button"> Отмени </Link>
|
||
{/* delete */}
|
||
<button className="button bg-red-500 hover:bg-red-700 focus:outline-none focus:shadow-outline" type="button" onClick={() => setIsModalOpen(true)}>
|
||
Изтрий
|
||
</button>
|
||
<ConfirmationModal
|
||
isOpen={isModalOpen}
|
||
onClose={() => setIsModalOpen(false)}
|
||
onConfirm={handleDelete}
|
||
message="Сигурни ли сте, че искате да изтриете този профил? Това действие не може да бъде отменено."
|
||
/>
|
||
|
||
{/* save */}
|
||
<button className="button bg-blue-500 hover:bg-blue-700 focus:outline-none focus:shadow-outline" type="submit">
|
||
{router.query?.id ? "Запази" : "Създай"}
|
||
</button>
|
||
</div>
|
||
</form>
|
||
|
||
<div className="flex flex-col">
|
||
<div className="flex flex-row">
|
||
<div className="flex-col" id="shiftlist" >
|
||
<div className="">
|
||
<ShiftsList assignments={publisher.assignments} selectedtab={common.getCurrentYearMonth()} />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div className="flex-1 p-5">
|
||
<AvailabilityList publisher={publisher} />
|
||
</div>
|
||
</div>
|
||
</div >
|
||
</div >
|
||
</>
|
||
)
|
||
};
|
||
|
||
|