From c5a5a5f5742ca887f6dd57d6b910a554243c4746 Mon Sep 17 00:00:00 2001
From: Sachintha Lakmin <68807141+sachintha-lk@users.noreply.github.com>
Date: Tue, 12 Nov 2024 16:23:44 +0530
Subject: [PATCH 1/6] Add sponsor form modal. Create new sponsor basics working
---
src/app/admin/dashboard/sponsors/page.tsx | 5 +-
.../ui/modals/sponsor-add-update-modal.tsx | 167 ++++++++++++++----
2 files changed, 136 insertions(+), 36 deletions(-)
diff --git a/src/app/admin/dashboard/sponsors/page.tsx b/src/app/admin/dashboard/sponsors/page.tsx
index c1346c5..c7a6290 100644
--- a/src/app/admin/dashboard/sponsors/page.tsx
+++ b/src/app/admin/dashboard/sponsors/page.tsx
@@ -59,8 +59,9 @@ export default async function ManageSponsors() {
-
-
+
+
+
diff --git a/src/components/ui/modals/sponsor-add-update-modal.tsx b/src/components/ui/modals/sponsor-add-update-modal.tsx
index 2d06316..3e0f4e7 100644
--- a/src/components/ui/modals/sponsor-add-update-modal.tsx
+++ b/src/components/ui/modals/sponsor-add-update-modal.tsx
@@ -1,21 +1,86 @@
"use client"
import React, { useState } from 'react';
+import { addSponsor } from '@/services/sponsors.service';
+import { SponsorLevel } from '@/interfaces/ISponsors';
function SponsorAddUpdateModal() {
const [isOpen, setIsOpen] = useState(false);
+ const [sponsorName, setSponsorName] = useState('');
+ const [sponsorLevel, setSponsorLevel] = useState('');
+ const [sponsorImageFile, setSponsorImageFile] = useState(null);
+ const [sponsorImgURL, setSponsorImgURL] = useState('');
+ // Handle file selection or drag-and-drop
+ const handleFileChange = (e: any) => {
+ e.preventDefault();
+
+ const file = e.target.files ? e.target.files[0] : e.dataTransfer.files[0];
+ if (file) {
+ setSponsorImageFile(file);
+ }
+ };
+
+ // Toggle modal visibility
const toggleModal = () => {
+ setSponsorName('');
+ setSponsorLevel('');
+ setSponsorImageFile(null);
+ setSponsorImgURL('');
+
setIsOpen(!isOpen);
- console.log('Modal toggled', isOpen);
};
+
+
+ const handleSubmit = async (e: React.FormEvent) => {
+
+ e.preventDefault();
+
+ if (!sponsorName || !sponsorLevel || !sponsorImageFile) {
+ return;
+ }
+
+ if (sponsorLevel !== 'Gold' && sponsorLevel !== 'Silver' && sponsorLevel !== 'Bronze') {
+ alert('Please select a valid sponsor level');
+ return;
+ }
+
+ // validate image file type
+ if (!sponsorImageFile.type.includes('image')) {
+ alert('Please select a valid image file');
+ return;
+ }
+
+ // validate image file size
+ if (sponsorImageFile.size > 1024 * 1024 * 2) {
+ alert('Please select an image file less than 2MB');
+ return;
+ }
+
+ // Upload image to firebase storage and get URL
+ // TODO implement image upload to firebase storage
+ const fakePlaceholderImgURL = "https://images.unsplash.com/photo-1726931467680-713bb3f432f5?q=80&w=400&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
+ const imgURL = fakePlaceholderImgURL;
+
+ // Create new sponsor object
+ const newSponsor = {
+ name: sponsorName,
+ level: sponsorLevel as SponsorLevel,
+ imgURL,
+ };
+
+ // Add new sponsor to firestore
+ await addSponsor(newSponsor);
+
+ }
+
return (
<>
- Toggle modal
+ Add Sponsor
{isOpen && (
@@ -23,7 +88,8 @@ function SponsorAddUpdateModal() {
id="crud-modal"
tabIndex={-1}
aria-hidden="true"
- className="fixed inset-0 z-50 flex justify-center items-center w-full h-full bg-black bg-opacity-50">
+ className="fixed inset-0 z-50 flex justify-center items-center w-full h-full bg-black bg-opacity-50"
+ >
@@ -41,7 +107,7 @@ function SponsorAddUpdateModal() {
-
+
)}
From 45f0b0818fca124b23787fe72dbcc5bcbe48512f Mon Sep 17 00:00:00 2001
From: Sachintha Lakmin <68807141+sachintha-lk@users.noreply.github.com>
Date: Tue, 12 Nov 2024 23:51:05 +0530
Subject: [PATCH 2/6] Add SponsorDeleteModal and refresh sponsor table after
delete and update
---
next.config.ts | 7 +
src/app/admin/dashboard/sponsors/page.tsx | 167 ++++++++++++------
.../modals/sponsor-add-update-modal.tsx | 16 +-
.../blocks/modals/sponsor-delete-modal.tsx | 120 +++++++++++++
4 files changed, 248 insertions(+), 62 deletions(-)
rename src/components/{ui => blocks}/modals/sponsor-add-update-modal.tsx (96%)
create mode 100644 src/components/blocks/modals/sponsor-delete-modal.tsx
diff --git a/next.config.ts b/next.config.ts
index 71ed172..33c32fe 100644
--- a/next.config.ts
+++ b/next.config.ts
@@ -10,11 +10,18 @@ const nextConfig: NextConfig = {
port: '',
pathname: '/images/**',
},
+ // THESE ARE FOR TEMP TESTING TODO REMOVE LATER
{
protocol: 'https',
hostname: 'fastly.picsum.photos',
port: '',
pathname: '/**',
+ },
+ {
+ protocol: 'https',
+ hostname: 'images.unsplash.com',
+ port: '',
+ pathname: '/**',
}
],
},
diff --git a/src/app/admin/dashboard/sponsors/page.tsx b/src/app/admin/dashboard/sponsors/page.tsx
index c7a6290..bb9c29f 100644
--- a/src/app/admin/dashboard/sponsors/page.tsx
+++ b/src/app/admin/dashboard/sponsors/page.tsx
@@ -1,69 +1,120 @@
+"use client"
+
import Image from "next/image";
-import { AdminDashboardLayout } from "../admin-dashboard-layout"
+import { AdminDashboardLayout } from "../admin-dashboard-layout";
import { getSponsors } from "@/services/sponsors.service";
-import { ISponsor } from "@/interfaces/ISponsors";
-import SponsorAddUpdateModal from "@/components/ui/modals/sponsor-add-update-modal";
+import { ISponsor } from "@/interfaces/ISponsors";
+import SponsorAddUpdateModal from "@/components/blocks/modals/sponsor-add-update-modal";
+import { useEffect, useState } from "react";
+import SponsorDeleteModal from "@/components/blocks/modals/sponsor-delete-modal";
+
+export default function ManageSponsors() {
+ const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
+ const [sponsorToDelete, setItemToDelete] = useState(null);
+ const [sponsors, setSponsors] = useState([] as ISponsor[]);
+ const [refresh, setRefresh] = useState(false); // State to trigger re-fetch
+
+ useEffect(() => {
+ getSponsors("All").then((data) => {
+ setSponsors(data);
+ }
+ );
+ }, [refresh]);
+
+ const refreshData = () => {
+ setRefresh(!refresh); // run useEffect again to refresh list
+ };
+
+ const handleDeleteClick = (sponsor: ISponsor) => {
+ setItemToDelete(sponsor);
+ setIsDeleteModalOpen(true);
+ refreshData();
+ };
+
+ const closeDeleteModal = () => {
+ setIsDeleteModalOpen(false);
+ setItemToDelete(null);
+ };
+
-export default async function ManageSponsors() {
-
- let sponsors: ISponsor[] = await getSponsors("All", 100); // implement pagination later for now 100
return (
-
-
Sponsors
-
Manage Sponsors here
- {/*
Deliver great service experiences fast - without the complexity of traditional ITSM solutions. Accelerate critical development work, eliminate toil, and deploy changes with ease.
*/}
+
+
Sponsors
+
Manage Sponsors here
+ {/*
Deliver great service experiences fast - without the complexity of traditional ITSM solutions. Accelerate critical development work, eliminate toil, and deploy changes with ease.
*/}
-
-
-
-
- Sponsor name
-
-
- Image
-
-
- Sponsor Level
-
-
- Created Time
-
-
- Action
-
-
-
-
- {sponsors.map((sponsor) => (
-
-
- {sponsor.name}
-
-
-
-
-
- {sponsor.level}
-
-
- {sponsor.timestamp?.toDate().toLocaleString()}
-
-
- Delete
-
-
- ))}
-
-
-
-
-
-
-
-
+
+
+
+
+ Sponsor name
+
+
+ Image
+
+
+ Sponsor Level
+
+
+ Created Time
+
+
+ Action
+
+
+
+
+ {sponsors.map((sponsor) => (
+
+
+ {sponsor.name}
+
+
+
+
+ {sponsor.level}
+
+ {sponsor.timestamp?.toDate().toLocaleString()}
+
+
+ handleDeleteClick(sponsor)
+ }>
+ Delete
+
+
+
+ ))}
+
+
+
+
+
+
+ {isDeleteModalOpen && sponsorToDelete && (
+
+ )}
+
);
}
diff --git a/src/components/ui/modals/sponsor-add-update-modal.tsx b/src/components/blocks/modals/sponsor-add-update-modal.tsx
similarity index 96%
rename from src/components/ui/modals/sponsor-add-update-modal.tsx
rename to src/components/blocks/modals/sponsor-add-update-modal.tsx
index 3e0f4e7..1bdb1d3 100644
--- a/src/components/ui/modals/sponsor-add-update-modal.tsx
+++ b/src/components/blocks/modals/sponsor-add-update-modal.tsx
@@ -3,7 +3,7 @@ import React, { useState } from 'react';
import { addSponsor } from '@/services/sponsors.service';
import { SponsorLevel } from '@/interfaces/ISponsors';
-function SponsorAddUpdateModal() {
+function SponsorAddUpdateModal({onAddSponsor}: {onAddSponsor: () => void}) {
const [isOpen, setIsOpen] = useState(false);
const [sponsorName, setSponsorName] = useState('');
@@ -61,7 +61,6 @@ function SponsorAddUpdateModal() {
// TODO implement image upload to firebase storage
const fakePlaceholderImgURL = "https://images.unsplash.com/photo-1726931467680-713bb3f432f5?q=80&w=400&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
const imgURL = fakePlaceholderImgURL;
-
// Create new sponsor object
const newSponsor = {
name: sponsorName,
@@ -70,7 +69,17 @@ function SponsorAddUpdateModal() {
};
// Add new sponsor to firestore
- await addSponsor(newSponsor);
+ addSponsor(newSponsor)
+ .then(() => {
+ console.log('Sponsor added successfully');
+ onAddSponsor();
+ toggleModal();
+ })
+ .catch((error) => {
+ console.error('Error adding sponsor: ', error);
+ alert('Error adding sponsor');
+ toggleModal();
+ });
}
@@ -129,7 +138,6 @@ function SponsorAddUpdateModal() {
value={sponsorLevel}
onChange={(e) => setSponsorLevel(e.target.value)}
className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white"
- defaultValue=""
required
>
Select Level
diff --git a/src/components/blocks/modals/sponsor-delete-modal.tsx b/src/components/blocks/modals/sponsor-delete-modal.tsx
new file mode 100644
index 0000000..c0a9292
--- /dev/null
+++ b/src/components/blocks/modals/sponsor-delete-modal.tsx
@@ -0,0 +1,120 @@
+"use client"
+import React, { useState } from 'react';
+import { deleteSponsor } from '@/services/sponsors.service';
+import { ISponsor } from '@/interfaces/ISponsors';
+
+function SponsorDeleteModal(
+ {sponsor, onClose, onDelete }: {sponsor: ISponsor, onClose: () => void, onDelete: () => void}
+) {
+
+ const [sponsorToDelete, setSponsorToDelete] = useState(sponsor);
+
+ const toggleModal = () => {
+ setSponsorToDelete(null);
+ onClose();
+ };
+
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+
+ if (sponsorToDelete?.id) {
+ deleteSponsor(sponsorToDelete.id)
+ .then(() => {
+ console.log("Sponsor deleted successfully");
+ onDelete();
+ toggleModal();
+ })
+ .catch((error) => {
+ console.error("Error deleting sponsor: ", error);
+ alert("Error deleting sponsor");
+ toggleModal();
+ });
+
+ } else {
+ console.error("Sponsor ID is undefined");
+ }
+
+ }
+
+ return (
+ <>
+
+
+
+
+
+ Delete Sponsor
+
+
+
+
+
+ Close modal
+
+
+
+
+
+
+
+ >
+ );
+}
+
+export default SponsorDeleteModal;
\ No newline at end of file
From a7cc16887169a62d2db6eb546e7c138395192300 Mon Sep 17 00:00:00 2001
From: Sachintha Lakmin <68807141+sachintha-lk@users.noreply.github.com>
Date: Tue, 12 Nov 2024 16:23:44 +0530
Subject: [PATCH 3/6] Add sponsor form modal. Create new sponsor basics working
---
src/app/admin/dashboard/sponsors/page.tsx | 5 +-
.../ui/modals/sponsor-add-update-modal.tsx | 167 ++++++++++++++----
2 files changed, 136 insertions(+), 36 deletions(-)
diff --git a/src/app/admin/dashboard/sponsors/page.tsx b/src/app/admin/dashboard/sponsors/page.tsx
index c1346c5..c7a6290 100644
--- a/src/app/admin/dashboard/sponsors/page.tsx
+++ b/src/app/admin/dashboard/sponsors/page.tsx
@@ -59,8 +59,9 @@ export default async function ManageSponsors() {
-
-
+
+
+
diff --git a/src/components/ui/modals/sponsor-add-update-modal.tsx b/src/components/ui/modals/sponsor-add-update-modal.tsx
index 2d06316..3e0f4e7 100644
--- a/src/components/ui/modals/sponsor-add-update-modal.tsx
+++ b/src/components/ui/modals/sponsor-add-update-modal.tsx
@@ -1,21 +1,86 @@
"use client"
import React, { useState } from 'react';
+import { addSponsor } from '@/services/sponsors.service';
+import { SponsorLevel } from '@/interfaces/ISponsors';
function SponsorAddUpdateModal() {
const [isOpen, setIsOpen] = useState(false);
+ const [sponsorName, setSponsorName] = useState('');
+ const [sponsorLevel, setSponsorLevel] = useState('');
+ const [sponsorImageFile, setSponsorImageFile] = useState(null);
+ const [sponsorImgURL, setSponsorImgURL] = useState('');
+ // Handle file selection or drag-and-drop
+ const handleFileChange = (e: any) => {
+ e.preventDefault();
+
+ const file = e.target.files ? e.target.files[0] : e.dataTransfer.files[0];
+ if (file) {
+ setSponsorImageFile(file);
+ }
+ };
+
+ // Toggle modal visibility
const toggleModal = () => {
+ setSponsorName('');
+ setSponsorLevel('');
+ setSponsorImageFile(null);
+ setSponsorImgURL('');
+
setIsOpen(!isOpen);
- console.log('Modal toggled', isOpen);
};
+
+
+ const handleSubmit = async (e: React.FormEvent) => {
+
+ e.preventDefault();
+
+ if (!sponsorName || !sponsorLevel || !sponsorImageFile) {
+ return;
+ }
+
+ if (sponsorLevel !== 'Gold' && sponsorLevel !== 'Silver' && sponsorLevel !== 'Bronze') {
+ alert('Please select a valid sponsor level');
+ return;
+ }
+
+ // validate image file type
+ if (!sponsorImageFile.type.includes('image')) {
+ alert('Please select a valid image file');
+ return;
+ }
+
+ // validate image file size
+ if (sponsorImageFile.size > 1024 * 1024 * 2) {
+ alert('Please select an image file less than 2MB');
+ return;
+ }
+
+ // Upload image to firebase storage and get URL
+ // TODO implement image upload to firebase storage
+ const fakePlaceholderImgURL = "https://images.unsplash.com/photo-1726931467680-713bb3f432f5?q=80&w=400&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
+ const imgURL = fakePlaceholderImgURL;
+
+ // Create new sponsor object
+ const newSponsor = {
+ name: sponsorName,
+ level: sponsorLevel as SponsorLevel,
+ imgURL,
+ };
+
+ // Add new sponsor to firestore
+ await addSponsor(newSponsor);
+
+ }
+
return (
<>
- Toggle modal
+ Add Sponsor
{isOpen && (
@@ -23,7 +88,8 @@ function SponsorAddUpdateModal() {
id="crud-modal"
tabIndex={-1}
aria-hidden="true"
- className="fixed inset-0 z-50 flex justify-center items-center w-full h-full bg-black bg-opacity-50">
+ className="fixed inset-0 z-50 flex justify-center items-center w-full h-full bg-black bg-opacity-50"
+ >
@@ -41,7 +107,7 @@ function SponsorAddUpdateModal() {
-
+
)}
From 389bbdd4ad0f0b74faac2797a936dd7363671a7f Mon Sep 17 00:00:00 2001
From: Sachintha Lakmin <68807141+sachintha-lk@users.noreply.github.com>
Date: Tue, 12 Nov 2024 23:51:05 +0530
Subject: [PATCH 4/6] Add SponsorDeleteModal and refresh sponsor table after
delete and update
---
next.config.ts | 7 +
src/app/admin/dashboard/sponsors/page.tsx | 167 ++++++++++++------
.../modals/sponsor-add-update-modal.tsx | 16 +-
.../blocks/modals/sponsor-delete-modal.tsx | 120 +++++++++++++
4 files changed, 248 insertions(+), 62 deletions(-)
rename src/components/{ui => blocks}/modals/sponsor-add-update-modal.tsx (96%)
create mode 100644 src/components/blocks/modals/sponsor-delete-modal.tsx
diff --git a/next.config.ts b/next.config.ts
index 71ed172..33c32fe 100644
--- a/next.config.ts
+++ b/next.config.ts
@@ -10,11 +10,18 @@ const nextConfig: NextConfig = {
port: '',
pathname: '/images/**',
},
+ // THESE ARE FOR TEMP TESTING TODO REMOVE LATER
{
protocol: 'https',
hostname: 'fastly.picsum.photos',
port: '',
pathname: '/**',
+ },
+ {
+ protocol: 'https',
+ hostname: 'images.unsplash.com',
+ port: '',
+ pathname: '/**',
}
],
},
diff --git a/src/app/admin/dashboard/sponsors/page.tsx b/src/app/admin/dashboard/sponsors/page.tsx
index c7a6290..bb9c29f 100644
--- a/src/app/admin/dashboard/sponsors/page.tsx
+++ b/src/app/admin/dashboard/sponsors/page.tsx
@@ -1,69 +1,120 @@
+"use client"
+
import Image from "next/image";
-import { AdminDashboardLayout } from "../admin-dashboard-layout"
+import { AdminDashboardLayout } from "../admin-dashboard-layout";
import { getSponsors } from "@/services/sponsors.service";
-import { ISponsor } from "@/interfaces/ISponsors";
-import SponsorAddUpdateModal from "@/components/ui/modals/sponsor-add-update-modal";
+import { ISponsor } from "@/interfaces/ISponsors";
+import SponsorAddUpdateModal from "@/components/blocks/modals/sponsor-add-update-modal";
+import { useEffect, useState } from "react";
+import SponsorDeleteModal from "@/components/blocks/modals/sponsor-delete-modal";
+
+export default function ManageSponsors() {
+ const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
+ const [sponsorToDelete, setItemToDelete] = useState(null);
+ const [sponsors, setSponsors] = useState([] as ISponsor[]);
+ const [refresh, setRefresh] = useState(false); // State to trigger re-fetch
+
+ useEffect(() => {
+ getSponsors("All").then((data) => {
+ setSponsors(data);
+ }
+ );
+ }, [refresh]);
+
+ const refreshData = () => {
+ setRefresh(!refresh); // run useEffect again to refresh list
+ };
+
+ const handleDeleteClick = (sponsor: ISponsor) => {
+ setItemToDelete(sponsor);
+ setIsDeleteModalOpen(true);
+ refreshData();
+ };
+
+ const closeDeleteModal = () => {
+ setIsDeleteModalOpen(false);
+ setItemToDelete(null);
+ };
+
-export default async function ManageSponsors() {
-
- let sponsors: ISponsor[] = await getSponsors("All", 100); // implement pagination later for now 100
return (
-
-
Sponsors
-
Manage Sponsors here
- {/*
Deliver great service experiences fast - without the complexity of traditional ITSM solutions. Accelerate critical development work, eliminate toil, and deploy changes with ease.
*/}
+
+
Sponsors
+
Manage Sponsors here
+ {/*
Deliver great service experiences fast - without the complexity of traditional ITSM solutions. Accelerate critical development work, eliminate toil, and deploy changes with ease.
*/}
-
-
-
-
- Sponsor name
-
-
- Image
-
-
- Sponsor Level
-
-
- Created Time
-
-
- Action
-
-
-
-
- {sponsors.map((sponsor) => (
-
-
- {sponsor.name}
-
-
-
-
-
- {sponsor.level}
-
-
- {sponsor.timestamp?.toDate().toLocaleString()}
-
-
- Delete
-
-
- ))}
-
-
-
-
-
-
-
-
+
+
+
+
+ Sponsor name
+
+
+ Image
+
+
+ Sponsor Level
+
+
+ Created Time
+
+
+ Action
+
+
+
+
+ {sponsors.map((sponsor) => (
+
+
+ {sponsor.name}
+
+
+
+
+ {sponsor.level}
+
+ {sponsor.timestamp?.toDate().toLocaleString()}
+
+
+ handleDeleteClick(sponsor)
+ }>
+ Delete
+
+
+
+ ))}
+
+
+
+
+
+
+ {isDeleteModalOpen && sponsorToDelete && (
+
+ )}
+
);
}
diff --git a/src/components/ui/modals/sponsor-add-update-modal.tsx b/src/components/blocks/modals/sponsor-add-update-modal.tsx
similarity index 96%
rename from src/components/ui/modals/sponsor-add-update-modal.tsx
rename to src/components/blocks/modals/sponsor-add-update-modal.tsx
index 3e0f4e7..1bdb1d3 100644
--- a/src/components/ui/modals/sponsor-add-update-modal.tsx
+++ b/src/components/blocks/modals/sponsor-add-update-modal.tsx
@@ -3,7 +3,7 @@ import React, { useState } from 'react';
import { addSponsor } from '@/services/sponsors.service';
import { SponsorLevel } from '@/interfaces/ISponsors';
-function SponsorAddUpdateModal() {
+function SponsorAddUpdateModal({onAddSponsor}: {onAddSponsor: () => void}) {
const [isOpen, setIsOpen] = useState(false);
const [sponsorName, setSponsorName] = useState('');
@@ -61,7 +61,6 @@ function SponsorAddUpdateModal() {
// TODO implement image upload to firebase storage
const fakePlaceholderImgURL = "https://images.unsplash.com/photo-1726931467680-713bb3f432f5?q=80&w=400&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
const imgURL = fakePlaceholderImgURL;
-
// Create new sponsor object
const newSponsor = {
name: sponsorName,
@@ -70,7 +69,17 @@ function SponsorAddUpdateModal() {
};
// Add new sponsor to firestore
- await addSponsor(newSponsor);
+ addSponsor(newSponsor)
+ .then(() => {
+ console.log('Sponsor added successfully');
+ onAddSponsor();
+ toggleModal();
+ })
+ .catch((error) => {
+ console.error('Error adding sponsor: ', error);
+ alert('Error adding sponsor');
+ toggleModal();
+ });
}
@@ -129,7 +138,6 @@ function SponsorAddUpdateModal() {
value={sponsorLevel}
onChange={(e) => setSponsorLevel(e.target.value)}
className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white"
- defaultValue=""
required
>
Select Level
diff --git a/src/components/blocks/modals/sponsor-delete-modal.tsx b/src/components/blocks/modals/sponsor-delete-modal.tsx
new file mode 100644
index 0000000..c0a9292
--- /dev/null
+++ b/src/components/blocks/modals/sponsor-delete-modal.tsx
@@ -0,0 +1,120 @@
+"use client"
+import React, { useState } from 'react';
+import { deleteSponsor } from '@/services/sponsors.service';
+import { ISponsor } from '@/interfaces/ISponsors';
+
+function SponsorDeleteModal(
+ {sponsor, onClose, onDelete }: {sponsor: ISponsor, onClose: () => void, onDelete: () => void}
+) {
+
+ const [sponsorToDelete, setSponsorToDelete] = useState(sponsor);
+
+ const toggleModal = () => {
+ setSponsorToDelete(null);
+ onClose();
+ };
+
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+
+ if (sponsorToDelete?.id) {
+ deleteSponsor(sponsorToDelete.id)
+ .then(() => {
+ console.log("Sponsor deleted successfully");
+ onDelete();
+ toggleModal();
+ })
+ .catch((error) => {
+ console.error("Error deleting sponsor: ", error);
+ alert("Error deleting sponsor");
+ toggleModal();
+ });
+
+ } else {
+ console.error("Sponsor ID is undefined");
+ }
+
+ }
+
+ return (
+ <>
+
+
+
+
+
+ Delete Sponsor
+
+
+
+
+
+ Close modal
+
+
+
+
+
+
+
+ >
+ );
+}
+
+export default SponsorDeleteModal;
\ No newline at end of file
From 588a8657b03b8fbbfb0b899081dbb7f8bcb1c046 Mon Sep 17 00:00:00 2001
From: Sachintha Lakmin <68807141+sachintha-lk@users.noreply.github.com>
Date: Wed, 13 Nov 2024 01:35:51 +0530
Subject: [PATCH 5/6] integrated img upload in adding sponsors
---
next.config.ts | 6 ++
.../modals/sponsor-add-update-modal.tsx | 56 +++++++++++--------
.../blocks/modals/sponsor-delete-modal.tsx | 42 +++++++++++++-
src/services/firebaseStorage.service.ts | 13 ++++-
4 files changed, 93 insertions(+), 24 deletions(-)
diff --git a/next.config.ts b/next.config.ts
index 33c32fe..85a986b 100644
--- a/next.config.ts
+++ b/next.config.ts
@@ -10,6 +10,12 @@ const nextConfig: NextConfig = {
port: '',
pathname: '/images/**',
},
+ {
+ protocol: 'https',
+ hostname: 'firebasestorage.googleapis.com',
+ port: '',
+ pathname: '/**',
+ },
// THESE ARE FOR TEMP TESTING TODO REMOVE LATER
{
protocol: 'https',
diff --git a/src/components/blocks/modals/sponsor-add-update-modal.tsx b/src/components/blocks/modals/sponsor-add-update-modal.tsx
index 1bdb1d3..ecc3106 100644
--- a/src/components/blocks/modals/sponsor-add-update-modal.tsx
+++ b/src/components/blocks/modals/sponsor-add-update-modal.tsx
@@ -2,6 +2,8 @@
import React, { useState } from 'react';
import { addSponsor } from '@/services/sponsors.service';
import { SponsorLevel } from '@/interfaces/ISponsors';
+import { addFile } from '@/services/firebaseStorage.service';
+import { getDownloadURL } from 'firebase/storage';
function SponsorAddUpdateModal({onAddSponsor}: {onAddSponsor: () => void}) {
@@ -58,28 +60,38 @@ function SponsorAddUpdateModal({onAddSponsor}: {onAddSponsor: () => void}) {
}
// Upload image to firebase storage and get URL
- // TODO implement image upload to firebase storage
- const fakePlaceholderImgURL = "https://images.unsplash.com/photo-1726931467680-713bb3f432f5?q=80&w=400&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
- const imgURL = fakePlaceholderImgURL;
- // Create new sponsor object
- const newSponsor = {
- name: sponsorName,
- level: sponsorLevel as SponsorLevel,
- imgURL,
- };
-
- // Add new sponsor to firestore
- addSponsor(newSponsor)
- .then(() => {
- console.log('Sponsor added successfully');
- onAddSponsor();
- toggleModal();
- })
- .catch((error) => {
- console.error('Error adding sponsor: ', error);
- alert('Error adding sponsor');
- toggleModal();
- });
+ addFile(sponsorImageFile).then((ref) => {
+ if (ref) {
+ console.log("StorageReference :",ref);
+ getDownloadURL(ref).then((url) => {
+ console.log('Image URL: ', url);
+
+ // Create new sponsor object
+ const newSponsor = {
+ name: sponsorName,
+ level: sponsorLevel as SponsorLevel,
+ imgURL: url,
+ };
+
+ // Add new sponsor to firestore
+ addSponsor(newSponsor)
+ .then(() => {
+ console.log('Sponsor added successfully', newSponsor);
+ onAddSponsor();
+ toggleModal();
+ })
+ .catch((error) => {
+ console.error('Error adding sponsor: ', error);
+ alert('Error adding sponsor');
+ toggleModal();
+ });
+ });
+ }
+ }).catch((error) => {
+ console.error('Error uploading file: ', error);
+ alert('Error uploading file');
+ return;
+ });
}
diff --git a/src/components/blocks/modals/sponsor-delete-modal.tsx b/src/components/blocks/modals/sponsor-delete-modal.tsx
index c0a9292..8647dd4 100644
--- a/src/components/blocks/modals/sponsor-delete-modal.tsx
+++ b/src/components/blocks/modals/sponsor-delete-modal.tsx
@@ -2,6 +2,7 @@
import React, { useState } from 'react';
import { deleteSponsor } from '@/services/sponsors.service';
import { ISponsor } from '@/interfaces/ISponsors';
+// import { deleteFile , getFileReferenceByUrl } from '@/services/firebaseStorage.service';
function SponsorDeleteModal(
{sponsor, onClose, onDelete }: {sponsor: ISponsor, onClose: () => void, onDelete: () => void}
@@ -17,7 +18,46 @@ function SponsorDeleteModal(
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
-
+
+ // if (sponsorToDelete?.id) {
+ // if img url is not null, delete the image from storage
+ // if (sponsorToDelete.imgURL) {
+ // getFileReferenceByUrl(sponsorToDelete.imgURL)
+ // .then((fileRef) => {
+ // if (fileRef) {
+ // deleteFile(fileRef)
+ // .then((res) => {
+ // if (res) {
+ // console.log("Image deleted successfully", sponsorToDelete.imgURL);
+
+ // delete the sponsor from the database
+ // if (sponsorToDelete?.id) {
+ // deleteSponsor(sponsorToDelete.id)
+ // .then(() => {
+ // console.log("Sponsor deleted successfully");
+ // onDelete();
+ // toggleModal();
+ // })
+ // .catch((error) => {
+ // console.error("Error deleting sponsor: ", error);
+ // alert("Error deleting sponsor");
+ // toggleModal();
+ // });
+ // }
+ // } else {
+ // console.error("Error deleting image");
+ // }
+ // });
+ // } else {
+ // console.error("File reference is null");
+ // }
+ // });
+
+
+ // } else {
+ // console.error("Sponsor ID is undefined");
+ // }
+
if (sponsorToDelete?.id) {
deleteSponsor(sponsorToDelete.id)
.then(() => {
diff --git a/src/services/firebaseStorage.service.ts b/src/services/firebaseStorage.service.ts
index 9dd2421..bfaa67d 100644
--- a/src/services/firebaseStorage.service.ts
+++ b/src/services/firebaseStorage.service.ts
@@ -30,4 +30,15 @@ export const deleteFile = async (fileRef:StorageReference):Promise=>{
return false;
});
return false;
-}
\ No newline at end of file
+}
+
+// export const getFileReferenceByUrl = async (fileUrl: string): Promise => {
+// // Extract the file path from the download URL
+// const url = new URL(fileUrl);
+// const path = decodeURIComponent(url.pathname.split('/o/')[1].split('?')[0]);
+
+// // Create a reference to the file using the extracted path
+// const fileRef = ref(storage, path);
+
+// return fileRef;
+// }
From 4d81afa4abab5f7cebc93d1f537eda2c9bc34df9 Mon Sep 17 00:00:00 2001
From: Sachintha Lakmin <68807141+sachintha-lk@users.noreply.github.com>
Date: Wed, 13 Nov 2024 08:48:03 +0530
Subject: [PATCH 6/6] Integrate with image deletion logic in SponsorDeleteModal
---
src/app/admin/dashboard/sponsors/page.tsx | 10 +-
.../blocks/modals/sponsor-delete-modal.tsx | 113 +++++++++---------
src/services/firebaseStorage.service.ts | 19 ++-
3 files changed, 77 insertions(+), 65 deletions(-)
diff --git a/src/app/admin/dashboard/sponsors/page.tsx b/src/app/admin/dashboard/sponsors/page.tsx
index bb9c29f..99039af 100644
--- a/src/app/admin/dashboard/sponsors/page.tsx
+++ b/src/app/admin/dashboard/sponsors/page.tsx
@@ -67,7 +67,7 @@ export default function ManageSponsors() {
- {sponsors.map((sponsor) => (
+ {sponsors.length > 0 && sponsors.map((sponsor) => (
))}
+
+ {sponsors.length === 0 && (
+
+
+ No sponsors found
+
+
+ )}
diff --git a/src/components/blocks/modals/sponsor-delete-modal.tsx b/src/components/blocks/modals/sponsor-delete-modal.tsx
index 8647dd4..7b2e098 100644
--- a/src/components/blocks/modals/sponsor-delete-modal.tsx
+++ b/src/components/blocks/modals/sponsor-delete-modal.tsx
@@ -2,7 +2,7 @@
import React, { useState } from 'react';
import { deleteSponsor } from '@/services/sponsors.service';
import { ISponsor } from '@/interfaces/ISponsors';
-// import { deleteFile , getFileReferenceByUrl } from '@/services/firebaseStorage.service';
+import { deleteFile , getFileReferenceByUrl } from '@/services/firebaseStorage.service';
function SponsorDeleteModal(
{sponsor, onClose, onDelete }: {sponsor: ISponsor, onClose: () => void, onDelete: () => void}
@@ -19,62 +19,67 @@ function SponsorDeleteModal(
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
- // if (sponsorToDelete?.id) {
- // if img url is not null, delete the image from storage
- // if (sponsorToDelete.imgURL) {
- // getFileReferenceByUrl(sponsorToDelete.imgURL)
- // .then((fileRef) => {
- // if (fileRef) {
- // deleteFile(fileRef)
- // .then((res) => {
- // if (res) {
- // console.log("Image deleted successfully", sponsorToDelete.imgURL);
-
- // delete the sponsor from the database
- // if (sponsorToDelete?.id) {
- // deleteSponsor(sponsorToDelete.id)
- // .then(() => {
- // console.log("Sponsor deleted successfully");
- // onDelete();
- // toggleModal();
- // })
- // .catch((error) => {
- // console.error("Error deleting sponsor: ", error);
- // alert("Error deleting sponsor");
- // toggleModal();
- // });
- // }
- // } else {
- // console.error("Error deleting image");
- // }
- // });
- // } else {
- // console.error("File reference is null");
- // }
- // });
-
-
- // } else {
- // console.error("Sponsor ID is undefined");
- // }
-
if (sponsorToDelete?.id) {
- deleteSponsor(sponsorToDelete.id)
- .then(() => {
- console.log("Sponsor deleted successfully");
- onDelete();
- toggleModal();
- })
- .catch((error) => {
- console.error("Error deleting sponsor: ", error);
- alert("Error deleting sponsor");
- toggleModal();
- });
+ // if img url is not null, delete the image from storage and starts with firebasestorage.googleapis.com
+ if (sponsorToDelete.imgURL && sponsorToDelete.imgURL !== "" && sponsorToDelete.imgURL.startsWith("https://firebasestorage.googleapis.com")) {
+ getFileReferenceByUrl(sponsorToDelete.imgURL)
+ .then((fileRef) => {
+ if (fileRef) {
+ deleteFile(fileRef)
+ .then((res) => {
+ console.log("Res", res);
+ if (res == true) {
+ console.log("Image deleted successfully", sponsorToDelete.imgURL);
+
+ // delete the sponsor from the database
+ if (sponsorToDelete?.id) {
+ deleteSponsor(sponsorToDelete.id)
+ .then(() => {
+ console.log("Sponsor deleted successfully");
+ onDelete();
+ toggleModal();
+ })
+ .catch((error) => {
+ console.error("Error deleting sponsor: ", error);
+ alert("Error deleting sponsor");
+ toggleModal();
+ });
+ }
+ } else {
+ console.error("Error deleting image");
+ }
+ }).catch((error) => {
+ console.error("Error deleting image: ", error);
+ }
+ );
+ } else {
+ console.error("File reference is null");
+ }
+ });
+
+
+ } else {
+ console.error("Sponsor ID is undefined");
+ }
+
+ // if (sponsorToDelete?.id) {
+ // deleteSponsor(sponsorToDelete.id)
+ // .then(() => {
+ // console.log("Sponsor deleted successfully");
+ // onDelete();
+ // toggleModal();
+ // })
+ // .catch((error) => {
+ // console.error("Error deleting sponsor: ", error);
+ // alert("Error deleting sponsor");
+ // toggleModal();
+ // });
- } else {
- console.error("Sponsor ID is undefined");
- }
+ // } else {
+ // console.error("Sponsor ID is undefined");
+ // }
+ }
}
return (
diff --git a/src/services/firebaseStorage.service.ts b/src/services/firebaseStorage.service.ts
index bfaa67d..e8a8e7d 100644
--- a/src/services/firebaseStorage.service.ts
+++ b/src/services/firebaseStorage.service.ts
@@ -22,23 +22,22 @@ export const addFile = async (file: Blob | Uint8Array | ArrayBuffer):Promise=>{
- await deleteObject(fileRef).then(() => {
+ const status = await deleteObject(fileRef).then(() => {
console.log('File deleted');
return true;
}).catch((error) => {
console.error('Error deleting file: ', error);
return false;
});
- return false;
+ return status;
}
-// export const getFileReferenceByUrl = async (fileUrl: string): Promise => {
-// // Extract the file path from the download URL
-// const url = new URL(fileUrl);
-// const path = decodeURIComponent(url.pathname.split('/o/')[1].split('?')[0]);
+export const getFileReferenceByUrl = async (fileUrl: string): Promise => {
+ const url = new URL(fileUrl);
+ const path = decodeURIComponent(url.pathname.split('/o/')[1].split('?')[0]);
-// // Create a reference to the file using the extracted path
-// const fileRef = ref(storage, path);
+ // Create a reference to the file using the extracted path
+ const fileRef = ref(storage, path);
-// return fileRef;
-// }
+ return fileRef;
+}