diff --git a/components/publisher/PublisherForm.js b/components/publisher/PublisherForm.js index e851008..1e39d46 100644 --- a/components/publisher/PublisherForm.js +++ b/components/publisher/PublisherForm.js @@ -19,34 +19,6 @@ import { useSession } from "next-auth/react" // 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) { return this.reduce(function (groups, item) { const val = item[prop] @@ -59,9 +31,11 @@ Array.prototype.groupBy = function (prop) { 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); @@ -72,6 +46,9 @@ export default function PublisherForm({ item, me }) { 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(); @@ -113,15 +90,17 @@ export default function PublisherForm({ item, me }) { publisher.availabilities = undefined; publisher.assignments = undefined; - let { familyHeadId, userId, ...rest } = publisher; + let { familyHeadId, userId, congregationId, ...rest } = publisher; // Set the familyHead relation based on the selected head const familyHeadRelation = familyHeadId ? { connect: { id: familyHeadId } } : { 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 rest = { ...rest, familyHead: familyHeadRelation, - user: userRel + user: userRel, + congregation: congregationRel }; try { @@ -246,6 +225,19 @@ export default function PublisherForm({ item, me }) { +
+ + +
+ + {/* notifications */}
diff --git a/pages/api/auth/[...nextauth].ts b/pages/api/auth/[...nextauth].ts index 8cb4f4d..098b95b 100644 --- a/pages/api/auth/[...nextauth].ts +++ b/pages/api/auth/[...nextauth].ts @@ -56,11 +56,11 @@ export const authOptions: NextAuthOptions = { keyId: process.env.APPLE_KEY_ID, } }), - // AzureADProvider({ - // clientId: process.env.AZURE_AD_CLIENT_ID, - // clientSecret: process.env.AZURE_AD_CLIENT_SECRET, - // tenantId: process.env.AZURE_AD_TENANT_ID, - // }), + AzureADProvider({ + clientId: process.env.AZURE_AD_CLIENT_ID, + clientSecret: process.env.AZURE_AD_CLIENT_SECRET, + tenantId: process.env.AZURE_AD_TENANT_ID, + }), CredentialsProvider({ id: 'credentials', // The name to display on the sign in form (e.g. 'Sign in with...') diff --git a/pages/auth/signin.tsx b/pages/auth/signin.tsx index 9904a52..ceccfdd 100644 --- a/pages/auth/signin.tsx +++ b/pages/auth/signin.tsx @@ -74,6 +74,13 @@ export default function SignIn({ csrfToken }) { src="https://authjs.dev/img/providers/apple.svg" className="mr-2" /> Влез чрез Apple */} + {/* microsoft */} + {/* */}

diff --git a/pages/cart/locations/index.tsx b/pages/cart/locations/index.tsx index 716993a..e6b5b44 100644 --- a/pages/cart/locations/index.tsx +++ b/pages/cart/locations/index.tsx @@ -4,6 +4,7 @@ import Layout from "../../../components/layout"; import LocationCard from "../../../components/location/LocationCard"; import axiosServer from '../../../src/axiosServer'; import ProtectedRoute from '../../../components/protectedRoute'; +import CongregationCRUD from "../publishers/congregationCRUD"; interface IProps { item: Location; } @@ -32,6 +33,7 @@ function LocationsPage({ items = [] }: IProps) {
+ ); } diff --git a/pages/cart/publishers/congregationCRUD.tsx b/pages/cart/publishers/congregationCRUD.tsx new file mode 100644 index 0000000..95d0e43 --- /dev/null +++ b/pages/cart/publishers/congregationCRUD.tsx @@ -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 ( + +
+
+

Сборове

+
+ setNewCongregation(e.target.value)} + placeholder="Име на сбор" + className="px-4 py-2 rounded-md border border-gray-300" + /> + +
+ + + + + + + + + {congregations.map((congregation) => ( + + + + + ))} + +
ИмеДействия
{congregation.name} + {/* */} + +
+
+
+
+ ); +} + diff --git a/prisma/migrations/20240510131656_publisher_congregation/migration.sql b/prisma/migrations/20240510131656_publisher_congregation/migration.sql new file mode 100644 index 0000000..133bedf --- /dev/null +++ b/prisma/migrations/20240510131656_publisher_congregation/migration.sql @@ -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; \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 391079f..8341d0d 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -124,6 +124,18 @@ model Publisher { EventLog EventLog[] lastLogin DateTime? 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 { @@ -181,23 +193,25 @@ model Shift { //date DateTime reportId Int? @unique Report Report? @relation(fields: [reportId], references: [id]) - isPublished Boolean @default(false) //NEW v1.0.1 + isPublished Boolean @default(false) EventLog EventLog[] @@map("Shift") } model Assignment { - id Int @id @default(autoincrement()) - shift Shift @relation(fields: [shiftId], references: [id], onDelete: Cascade) - shiftId Int - publisher Publisher @relation(fields: [publisherId], references: [id], onDelete: Cascade) - publisherId String - isBySystem Boolean @default(false) // if no availability for it, when importing previous schedules - isConfirmed Boolean @default(false) - isWithTransport Boolean @default(false) - isMailSent Boolean @default(false) - publicGuid String? @unique + id Int @id @default(autoincrement()) + shift Shift @relation(fields: [shiftId], references: [id], onDelete: Cascade) + shiftId Int + publisher Publisher @relation(fields: [publisherId], references: [id], onDelete: Cascade) + publisherId String + isBySystem Boolean @default(false) // if no availability for it, when importing previous schedules + isConfirmed Boolean @default(false) + isWithTransport Boolean @default(false) + isMailSent Boolean @default(false) + 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") } @@ -237,6 +251,7 @@ model Report { experienceInfo String? @db.LongText type ReportType @default(ServiceReport) + comments String? @@map("Report") } @@ -258,6 +273,7 @@ model Message { isRead Boolean @default(false) isPublic Boolean @default(false) type MessageType @default(Email) + publicUntil DateTime? } enum EventLogType {