Added congregation table and field
This commit is contained in:
@ -19,34 +19,6 @@ import { useSession } from "next-auth/react"
|
|||||||
|
|
||||||
// import { Tabs, List } from 'tw-elements'
|
// import { Tabs, List } from 'tw-elements'
|
||||||
|
|
||||||
// model Publisher {
|
|
||||||
// id String @id @default(cuid())
|
|
||||||
// firstName String
|
|
||||||
// lastName String
|
|
||||||
// email String @unique
|
|
||||||
// phone String?
|
|
||||||
// isActive Boolean @default(true)
|
|
||||||
// isImported Boolean @default(false)
|
|
||||||
// age Int?
|
|
||||||
// availabilities Availability[]
|
|
||||||
// assignments Assignment[]
|
|
||||||
|
|
||||||
// emailVerified DateTime?
|
|
||||||
// accounts Account[]
|
|
||||||
// sessions Session[]
|
|
||||||
// role UserRole @default(USER)
|
|
||||||
// desiredShiftsPerMonth Int @default(4)
|
|
||||||
// isMale Boolean @default(true)
|
|
||||||
// isNameForeign Boolean @default(false)
|
|
||||||
|
|
||||||
// familyHeadId String? // Optional familyHeadId for each family member
|
|
||||||
// familyHead Publisher? @relation("FamilyMember", fields: [familyHeadId], references: [id])
|
|
||||||
// familyMembers Publisher[] @relation("FamilyMember")
|
|
||||||
// type PublisherType @default(Publisher)
|
|
||||||
// Town String?
|
|
||||||
// Comments String?
|
|
||||||
// }
|
|
||||||
|
|
||||||
Array.prototype.groupBy = function (prop) {
|
Array.prototype.groupBy = function (prop) {
|
||||||
return this.reduce(function (groups, item) {
|
return this.reduce(function (groups, item) {
|
||||||
const val = item[prop]
|
const val = item[prop]
|
||||||
@ -59,9 +31,11 @@ Array.prototype.groupBy = function (prop) {
|
|||||||
export default function PublisherForm({ item, me }) {
|
export default function PublisherForm({ item, me }) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { data: session } = useSession()
|
const { data: session } = useSession()
|
||||||
|
const [congregations, setCongregations] = useState([]);
|
||||||
|
|
||||||
const urls = {
|
const urls = {
|
||||||
apiUrl: "/api/data/publishers/",
|
apiUrl: "/api/data/publishers/",
|
||||||
|
congregationsUrl: "/api/data/congregations",
|
||||||
indexUrl: session?.user?.role == UserRole.ADMIN ? "/cart/publishers" : "/dash"
|
indexUrl: session?.user?.role == UserRole.ADMIN ? "/cart/publishers" : "/dash"
|
||||||
}
|
}
|
||||||
console.log("urls.indexUrl: " + urls.indexUrl);
|
console.log("urls.indexUrl: " + urls.indexUrl);
|
||||||
@ -72,6 +46,9 @@ export default function PublisherForm({ item, me }) {
|
|||||||
const h = (await import("../../src/helpers/const.js")).default;
|
const h = (await import("../../src/helpers/const.js")).default;
|
||||||
//console.log("fetchModules: " + JSON.stringify(h));
|
//console.log("fetchModules: " + JSON.stringify(h));
|
||||||
setHelper(h);
|
setHelper(h);
|
||||||
|
|
||||||
|
const response = await axiosInstance.get(urls.congregationsUrl);
|
||||||
|
setCongregations(response.data);
|
||||||
}
|
}
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchModules();
|
fetchModules();
|
||||||
@ -113,15 +90,17 @@ export default function PublisherForm({ item, me }) {
|
|||||||
publisher.availabilities = undefined;
|
publisher.availabilities = undefined;
|
||||||
publisher.assignments = undefined;
|
publisher.assignments = undefined;
|
||||||
|
|
||||||
let { familyHeadId, userId, ...rest } = publisher;
|
let { familyHeadId, userId, congregationId, ...rest } = publisher;
|
||||||
// Set the familyHead relation based on the selected head
|
// Set the familyHead relation based on the selected head
|
||||||
const familyHeadRelation = familyHeadId ? { connect: { id: familyHeadId } } : { disconnect: true };
|
const familyHeadRelation = familyHeadId ? { connect: { id: familyHeadId } } : { disconnect: true };
|
||||||
const userRel = userId ? { connect: { id: userId } } : { disconnect: true };
|
const userRel = userId ? { connect: { id: userId } } : { disconnect: true };
|
||||||
|
const congregationRel = congregationId ? { connect: { id: parseInt(congregationId) } } : { disconnect: true };
|
||||||
// Return the new state without familyHeadId and with the correct familyHead relation
|
// Return the new state without familyHeadId and with the correct familyHead relation
|
||||||
rest = {
|
rest = {
|
||||||
...rest,
|
...rest,
|
||||||
familyHead: familyHeadRelation,
|
familyHead: familyHeadRelation,
|
||||||
user: userRel
|
user: userRel,
|
||||||
|
congregation: congregationRel
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -246,6 +225,19 @@ export default function PublisherForm({ item, me }) {
|
|||||||
<label className="label" htmlFor="town">Град</label>
|
<label className="label" htmlFor="town">Град</label>
|
||||||
<input type="text" id="town" name="town" value={publisher.town} onChange={handleChange} className="textbox" placeholder="Град" autoFocus />
|
<input type="text" id="town" name="town" value={publisher.town} onChange={handleChange} className="textbox" placeholder="Град" autoFocus />
|
||||||
</div>
|
</div>
|
||||||
|
<div className="mb-4">
|
||||||
|
<label className="label" htmlFor="congregationId">Сбор</label>
|
||||||
|
<select id="congregationId" name="congregationId" value={publisher.congregationId} onChange={handleChange} className="select" placeholder="Община" autoFocus >
|
||||||
|
<option value="">Избери сбор</option>
|
||||||
|
{congregations.map((congregation) => (
|
||||||
|
<option key={congregation.id} value={congregation.id}>
|
||||||
|
{congregation.name}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{/* notifications */}
|
{/* notifications */}
|
||||||
<div className="mb-6 p-4 border border-gray-300 rounded-lg">
|
<div className="mb-6 p-4 border border-gray-300 rounded-lg">
|
||||||
|
@ -56,11 +56,11 @@ export const authOptions: NextAuthOptions = {
|
|||||||
keyId: process.env.APPLE_KEY_ID,
|
keyId: process.env.APPLE_KEY_ID,
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
// AzureADProvider({
|
AzureADProvider({
|
||||||
// clientId: process.env.AZURE_AD_CLIENT_ID,
|
clientId: process.env.AZURE_AD_CLIENT_ID,
|
||||||
// clientSecret: process.env.AZURE_AD_CLIENT_SECRET,
|
clientSecret: process.env.AZURE_AD_CLIENT_SECRET,
|
||||||
// tenantId: process.env.AZURE_AD_TENANT_ID,
|
tenantId: process.env.AZURE_AD_TENANT_ID,
|
||||||
// }),
|
}),
|
||||||
CredentialsProvider({
|
CredentialsProvider({
|
||||||
id: 'credentials',
|
id: 'credentials',
|
||||||
// The name to display on the sign in form (e.g. 'Sign in with...')
|
// The name to display on the sign in form (e.g. 'Sign in with...')
|
||||||
|
@ -74,6 +74,13 @@ export default function SignIn({ csrfToken }) {
|
|||||||
src="https://authjs.dev/img/providers/apple.svg" className="mr-2" />
|
src="https://authjs.dev/img/providers/apple.svg" className="mr-2" />
|
||||||
Влез чрез Apple
|
Влез чрез Apple
|
||||||
</button> */}
|
</button> */}
|
||||||
|
{/* microsoft */}
|
||||||
|
{/* <button onClick={() => signIn('azure-ad', { callbackUrl: '/' })}
|
||||||
|
className="mt-4 flex items-center justify-center w-full py-3 px-4 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50">
|
||||||
|
<img loading="lazy" height="24" width="24" alt="Microsoft logo"
|
||||||
|
src="https://authjs.dev/img/providers/azure-ad.svg" className="mr-2" />
|
||||||
|
Влез чрез Microsoft
|
||||||
|
</button> */}
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full max-w-xs mt-8 mb-8">
|
<div className="w-full max-w-xs mt-8 mb-8">
|
||||||
<hr className="border-t border-gray-300" />
|
<hr className="border-t border-gray-300" />
|
||||||
|
@ -4,6 +4,7 @@ import Layout from "../../../components/layout";
|
|||||||
import LocationCard from "../../../components/location/LocationCard";
|
import LocationCard from "../../../components/location/LocationCard";
|
||||||
import axiosServer from '../../../src/axiosServer';
|
import axiosServer from '../../../src/axiosServer';
|
||||||
import ProtectedRoute from '../../../components/protectedRoute';
|
import ProtectedRoute from '../../../components/protectedRoute';
|
||||||
|
import CongregationCRUD from "../publishers/congregationCRUD";
|
||||||
interface IProps {
|
interface IProps {
|
||||||
item: Location;
|
item: Location;
|
||||||
}
|
}
|
||||||
@ -32,6 +33,7 @@ function LocationsPage({ items = [] }: IProps) {
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</ProtectedRoute>
|
</ProtectedRoute>
|
||||||
|
<CongregationCRUD />
|
||||||
</Layout>
|
</Layout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
103
pages/cart/publishers/congregationCRUD.tsx
Normal file
103
pages/cart/publishers/congregationCRUD.tsx
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
// a simple CRUD componenet for congregations for admins
|
||||||
|
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import axiosInstance from '../../../src/axiosSecure';
|
||||||
|
import toast from 'react-hot-toast';
|
||||||
|
import Layout from '../../../components/layout';
|
||||||
|
import ProtectedRoute from '../../../components/protectedRoute';
|
||||||
|
import { UserRole } from '@prisma/client';
|
||||||
|
import { useRouter } from 'next/router';
|
||||||
|
|
||||||
|
export default function CongregationCRUD() {
|
||||||
|
const [congregations, setCongregations] = useState([]);
|
||||||
|
const [newCongregation, setNewCongregation] = useState('');
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const fetchCongregations = async () => {
|
||||||
|
try {
|
||||||
|
const { data: congregationsData } = await axiosInstance.get(`/api/data/congregations`);
|
||||||
|
setCongregations(congregationsData);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const addCongregation = async () => {
|
||||||
|
try {
|
||||||
|
await axiosInstance.post(`/api/data/congregations`, { name: newCongregation, address: "" });
|
||||||
|
toast.success('Успешно добавен сбор');
|
||||||
|
setNewCongregation('');
|
||||||
|
fetchCongregations();
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteCongregation = async (id) => {
|
||||||
|
try {
|
||||||
|
await axiosInstance.delete(`/api/data/congregations/${id}`);
|
||||||
|
toast.success('Успешно изтрит сбор');
|
||||||
|
fetchCongregations();
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
fetchCongregations();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ProtectedRoute allowedRoles={[UserRole.ADMIN]}>
|
||||||
|
<div className="h-5/6 grid place-items-start px-4 pt-8">
|
||||||
|
<div className="flex flex-col w-full px-4">
|
||||||
|
<h1 className="text-2xl font-bold text-center">Сборове</h1>
|
||||||
|
<div className="flex gap-2 mb-4">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={newCongregation}
|
||||||
|
onChange={(e) => setNewCongregation(e.target.value)}
|
||||||
|
placeholder="Име на сбор"
|
||||||
|
className="px-4 py-2 rounded-md border border-gray-300"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
onClick={addCongregation}
|
||||||
|
className="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded"
|
||||||
|
>
|
||||||
|
Добави
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<table className="w-full">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Име</th>
|
||||||
|
<th>Действия</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{congregations.map((congregation) => (
|
||||||
|
<tr key={congregation.id}>
|
||||||
|
<td>{congregation.name}</td>
|
||||||
|
<td className='right'>
|
||||||
|
{/* <button
|
||||||
|
onClick={() => router.push(`/cart/publishers/congregation/${congregation.id}`)}
|
||||||
|
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
|
||||||
|
>
|
||||||
|
Преглед
|
||||||
|
</button> */}
|
||||||
|
<button
|
||||||
|
onClick={() => deleteCongregation(congregation.id)}
|
||||||
|
className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded"
|
||||||
|
>
|
||||||
|
Изтрий
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ProtectedRoute>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE `Assignment`
|
||||||
|
ADD COLUMN `originalPublisherId` VARCHAR(191) NULL;
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE `Message` ADD COLUMN `publicUntil` DATETIME(3) NULL;
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE `Publisher`
|
||||||
|
ADD COLUMN `congregationId` INTEGER NULL,
|
||||||
|
ADD COLUMN `locale` VARCHAR(191) NULL DEFAULT 'bg';
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE `Report` ADD COLUMN `comments` VARCHAR(191) NULL;
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE `Congregation` (
|
||||||
|
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||||
|
`name` VARCHAR(191) NOT NULL,
|
||||||
|
`address` VARCHAR(191) NOT NULL,
|
||||||
|
`isActive` BOOLEAN NOT NULL DEFAULT true,
|
||||||
|
|
||||||
|
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE `Publisher`
|
||||||
|
ADD CONSTRAINT `Publisher_congregationId_fkey` FOREIGN KEY (`congregationId`) REFERENCES `Congregation` (`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE `Assignment`
|
||||||
|
ADD CONSTRAINT `Assignment_originalPublisherId_fkey` FOREIGN KEY (`originalPublisherId`) REFERENCES `Publisher` (`id`) ON DELETE SET NULL ON UPDATE CASCADE;
|
@ -124,6 +124,18 @@ model Publisher {
|
|||||||
EventLog EventLog[]
|
EventLog EventLog[]
|
||||||
lastLogin DateTime?
|
lastLogin DateTime?
|
||||||
pushSubscription Json?
|
pushSubscription Json?
|
||||||
|
originalAssignments Assignment[] @relation("OriginalPublisher")
|
||||||
|
congregation Congregation? @relation(fields: [congregationId], references: [id])
|
||||||
|
congregationId Int?
|
||||||
|
locale String? @default("bg")
|
||||||
|
}
|
||||||
|
|
||||||
|
model Congregation {
|
||||||
|
id Int @id @default(autoincrement())
|
||||||
|
name String
|
||||||
|
address String
|
||||||
|
isActive Boolean @default(true)
|
||||||
|
publishers Publisher[]
|
||||||
}
|
}
|
||||||
|
|
||||||
model Availability {
|
model Availability {
|
||||||
@ -181,23 +193,25 @@ model Shift {
|
|||||||
//date DateTime
|
//date DateTime
|
||||||
reportId Int? @unique
|
reportId Int? @unique
|
||||||
Report Report? @relation(fields: [reportId], references: [id])
|
Report Report? @relation(fields: [reportId], references: [id])
|
||||||
isPublished Boolean @default(false) //NEW v1.0.1
|
isPublished Boolean @default(false)
|
||||||
EventLog EventLog[]
|
EventLog EventLog[]
|
||||||
|
|
||||||
@@map("Shift")
|
@@map("Shift")
|
||||||
}
|
}
|
||||||
|
|
||||||
model Assignment {
|
model Assignment {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
shift Shift @relation(fields: [shiftId], references: [id], onDelete: Cascade)
|
shift Shift @relation(fields: [shiftId], references: [id], onDelete: Cascade)
|
||||||
shiftId Int
|
shiftId Int
|
||||||
publisher Publisher @relation(fields: [publisherId], references: [id], onDelete: Cascade)
|
publisher Publisher @relation(fields: [publisherId], references: [id], onDelete: Cascade)
|
||||||
publisherId String
|
publisherId String
|
||||||
isBySystem Boolean @default(false) // if no availability for it, when importing previous schedules
|
isBySystem Boolean @default(false) // if no availability for it, when importing previous schedules
|
||||||
isConfirmed Boolean @default(false)
|
isConfirmed Boolean @default(false)
|
||||||
isWithTransport Boolean @default(false)
|
isWithTransport Boolean @default(false)
|
||||||
isMailSent Boolean @default(false)
|
isMailSent Boolean @default(false)
|
||||||
publicGuid String? @unique
|
publicGuid String? @unique
|
||||||
|
originalPublisherId String? // New field to store the original publisher id when the assignment is replaced
|
||||||
|
originalPublisher Publisher? @relation("OriginalPublisher", fields: [originalPublisherId], references: [id])
|
||||||
|
|
||||||
@@map("Assignment")
|
@@map("Assignment")
|
||||||
}
|
}
|
||||||
@ -237,6 +251,7 @@ model Report {
|
|||||||
|
|
||||||
experienceInfo String? @db.LongText
|
experienceInfo String? @db.LongText
|
||||||
type ReportType @default(ServiceReport)
|
type ReportType @default(ServiceReport)
|
||||||
|
comments String?
|
||||||
|
|
||||||
@@map("Report")
|
@@map("Report")
|
||||||
}
|
}
|
||||||
@ -258,6 +273,7 @@ model Message {
|
|||||||
isRead Boolean @default(false)
|
isRead Boolean @default(false)
|
||||||
isPublic Boolean @default(false)
|
isPublic Boolean @default(false)
|
||||||
type MessageType @default(Email)
|
type MessageType @default(Email)
|
||||||
|
publicUntil DateTime?
|
||||||
}
|
}
|
||||||
|
|
||||||
enum EventLogType {
|
enum EventLogType {
|
||||||
|
Reference in New Issue
Block a user