diff --git a/api/routes/pages/pages.ts b/api/routes/pages/pages.ts index 8053176..a4bf945 100644 --- a/api/routes/pages/pages.ts +++ b/api/routes/pages/pages.ts @@ -1,14 +1,14 @@ -import express, { Request, Response } from 'express'; -import { PrismaClient, User } from '@prisma/client'; -import { nanoid } from 'nanoid'; -import auth from '../../middleware/auth'; -import { JWT } from 'google-auth-library'; -import { drive_v3, google } from 'googleapis'; -import multer, { memoryStorage } from 'multer'; -import { supabase } from '../..'; -import { v4 as uuidv4 } from 'uuid'; -import IPageCustomization from '../types/IPageCustomization'; -import serviceClient from '../../service'; +import express, { Request, Response } from "express"; +import { PrismaClient, User } from "@prisma/client"; +import { nanoid } from "nanoid"; +import auth from "../../middleware/auth"; +import { JWT } from "google-auth-library"; +import { drive_v3, google } from "googleapis"; +import multer, { memoryStorage } from "multer"; +import { supabase } from "../.."; +import { v4 as uuidv4 } from "uuid"; +import IPageCustomization from "../types/IPageCustomization"; +import serviceClient from "../../service"; const prisma = new PrismaClient(); export const router = express.Router(); @@ -16,32 +16,14 @@ export const router = express.Router(); const storage = memoryStorage(); const upload = multer({ storage }); -interface PageCustomization { - name: string; - organisationId: string; - sheetId: string; - sheetTabId: string; - backgroundColor?: string; - textFieldBackgroundColor?: string; - textColor?: string; - buttonColor?: string; - headingColor?: string; - logoLink?: string; - backgroundImageLink?: string; - fontFamily?: string; - identificatonColumns: { - originalName: string; - displayName?: string; - }[]; -} router.post( - '/create', + "/create", upload.fields([ { - name: 'background', + name: "background", }, { - name: 'logo', + name: "logo", }, ]), auth, @@ -69,7 +51,7 @@ router.post( return res .status(400) .send( - '`name`, `organisationId`, `sheetId`, `sheetTabId`, and `identificationColumns` are required fields' + "`name`, `organisationId`, `sheetId`, `sheetTabId`, and `identificationColumns` are required fields" ); // Check if the sheet id is already in use @@ -88,13 +70,13 @@ router.post( try { const drive = google.drive({ - version: 'v3', + version: "v3", auth: serviceClient, }); console.log(await drive.files.list()); const permissions = await drive.permissions.list({ fileId: sheetId, - fields: 'permissions(emailAddress)', + fields: "permissions(emailAddress)", }); const isSharedWithEmail = permissions.data.permissions!.some( (permission: drive_v3.Schema$Permission) => @@ -103,13 +85,13 @@ router.post( if (!isSharedWithEmail) return res .status(401) - .send('unauthorised to access this spreadsheet'); + .send("unauthorised to access this spreadsheet"); } catch (err) { console.error(err); return res .status(500) .send( - 'failed to check if sheet is shared with user. make sure this spreadsheet is shared with the service account.' + "failed to check if sheet is shared with user. make sure this spreadsheet is shared with the service account." ); } @@ -124,15 +106,15 @@ router.post( const fileName = background[0].originalname; const buffer = background[0].buffer; const { data, error } = await supabase.storage - .from('image-bucket') - .upload(`${uuidv4()}.${fileName.split('.').pop()}`, buffer, { - contentType: 'image/*', + .from("image-bucket") + .upload(`${uuidv4()}.${fileName.split(".").pop()}`, buffer, { + contentType: "image/*", }); if (error) { console.error(`Error: ${JSON.stringify(error)}`); return res .status(500) - .send('failed to upload background to storage bucket'); + .send("failed to upload background to storage bucket"); } backgroundUrl = storageBucketUrlPrefix + data.path; } @@ -141,15 +123,15 @@ router.post( const fileName = logo[0].originalname; const buffer = logo[0].buffer; const { data, error } = await supabase.storage - .from('image-bucket') - .upload(`${uuidv4()}.${fileName.split('.').pop()}`, buffer, { - contentType: 'image/*', + .from("image-bucket") + .upload(`${uuidv4()}.${fileName.split(".").pop()}`, buffer, { + contentType: "image/*", }); if (error) { console.error(`Error: ${JSON.stringify(error)}`); return res .status(500) - .send('failed to upload logo to storage bucket'); + .send("failed to upload logo to storage bucket"); } logoUrl = storageBucketUrlPrefix + data.path; } @@ -170,9 +152,10 @@ router.post( textColor: rest.textColor, buttonColor: rest.buttonColor, headingColor: rest.headingColor, + dropDownBackgroundColor: rest.dropDownBackgroundColor, logoLink: logoUrl, backgroundImageLink: backgroundUrl, - fontFamily: fontFamily || 'Montserrat', + fontFamily: fontFamily || "Montserrat", }, }); @@ -192,19 +175,19 @@ router.post( res.status(200).json({ pathId }); } catch (error) { console.error(`Error creating page: ${error}`); - res.status(400).json({ error: 'Error creating page' }); + res.status(400).json({ error: "Error creating page" }); } } ); router.get( - '/verify/:webLink/:columnName/:value', + "/verify/:webLink/:columnName/:value", async (req: Request, res: Response) => { const { webLink, columnName, value } = req.params; if (!webLink || !columnName || !value) return res .status(400) - .send('`pageId`, `columnName`, and `value` are required fields'); + .send("`pageId`, `columnName`, and `value` are required fields"); const page = await prisma.page.findFirst({ where: { @@ -216,7 +199,7 @@ router.get( return res.status(400).send(`could not find page with link ${webLink}`); // intialise credentials - const sheets = google.sheets({ version: 'v4', auth: serviceClient }); + const sheets = google.sheets({ version: "v4", auth: serviceClient }); const columnData: { [key: string]: { id: string; name: string; unique: boolean }; } = {}; @@ -233,7 +216,7 @@ router.get( if (!metadataResponse.data.sheets) { return res .status(400) - .send(JSON.stringify('spreadsheet has no sheets')); + .send(JSON.stringify("spreadsheet has no sheets")); } // Find the sheet ID that matches the given gid @@ -243,7 +226,7 @@ router.get( // If the sheet ID is not found, return an error if (!sheet) { - return res.status(404).send(JSON.stringify('sheet not found')); + return res.status(404).send(JSON.stringify("sheet not found")); } // Get the name of the sheet @@ -263,7 +246,7 @@ router.get( range, }); - if (!values) return res.status(500).send('club has no members'); + if (!values) return res.status(500).send("club has no members"); const originalColumn = await prisma.column.findFirst({ where: { @@ -300,7 +283,7 @@ router.get( try { return element.toLowerCase(); } catch (err) { - return ''; + return ""; } }) .includes(value.toLowerCase()) @@ -314,7 +297,7 @@ router.get( }, }); - return res.status(200).send('value found in column'); + return res.status(200).send("value found in column"); } else { await prisma.membershipCheckUsage.create({ data: { @@ -325,16 +308,16 @@ router.get( }, }); - return res.status(200).send('could not find user in column'); + return res.status(200).send("could not find user in column"); } } catch (err) { console.error(err); - return res.status(500).send('error retrieving data'); + return res.status(500).send("error retrieving data"); } } ); -router.get('/info/:webLink', async (req: Request, res: Response) => { +router.get("/info/:webLink", async (req: Request, res: Response) => { const { webLink } = req.params; const pageData = await prisma.page.findFirst({ @@ -344,7 +327,7 @@ router.get('/info/:webLink', async (req: Request, res: Response) => { }); if (!pageData) - return res.status(400).send('failed to get data with that link'); + return res.status(400).send("failed to get data with that link"); const columnData = await prisma.column.findMany({ where: { @@ -353,11 +336,12 @@ router.get('/info/:webLink', async (req: Request, res: Response) => { }); if (!columnData) - return res.status(400).send('failed to get columns data with that link'); + return res.status(400).send("failed to get columns data with that link"); const dataToReturn: any = { title: pageData?.name, backgroundColor: pageData?.backgroundColor, + dropDownBackgroundColor: pageData.dropDownBackgroundColor, textFieldBackgroundColor: pageData?.textFieldBackgroundColor, textFieldtextColor: pageData?.textColor, buttonColor: pageData?.buttonColor, diff --git a/api/routes/types/IPageCustomization.ts b/api/routes/types/IPageCustomization.ts index cf2e5f3..ddb9c2f 100644 --- a/api/routes/types/IPageCustomization.ts +++ b/api/routes/types/IPageCustomization.ts @@ -5,6 +5,7 @@ export default interface IPageCustomization { sheetTabId: string; backgroundColor?: string; textFieldBackgroundColor?: string; + dropDownBackgroundColor: string; textColor?: string; buttonColor?: string; headingColor?: string; diff --git a/client/src/pages/club-checker-page/ClubCheckerPage.tsx b/client/src/pages/club-checker-page/ClubCheckerPage.tsx index 20f96ea..8968df1 100644 --- a/client/src/pages/club-checker-page/ClubCheckerPage.tsx +++ b/client/src/pages/club-checker-page/ClubCheckerPage.tsx @@ -9,18 +9,18 @@ Component takes as props: Club ID, Club name, theme colours, club logo URL, opti Otherwise, users can click a check button to enter their info Users are presented with an error message if no info has been entered into the textfield/*/ -import { CircularProgress } from "@mui/material"; -import Button from '../../components/Button'; -import Textfield from '../../components/Textfield'; -import styles from './ClubCheckerPage.module.css'; -import { createRef, useEffect, useLayoutEffect, useRef, useState } from 'react'; -import { getTextColor } from '../../utils/helpers'; -import IColumn from '../../types/IColumn'; -import axios from 'axios'; -import { TickCircle, CloseCircle, InfoCircle } from 'iconsax-react'; -import { useNavigate, useParams } from 'react-router'; -import SadFace from '../../assets/SadFace.svg'; -import DeadFace from '../../assets/DeadFace.svg'; +import Button from "../../components/Button"; +import Textfield from "../../components/Textfield"; +import styles from "./ClubCheckerPage.module.css"; +import { createRef, useEffect, useLayoutEffect, useRef, useState } from "react"; +import { getTextColor } from "../../utils/helpers"; +import IColumn from "../../types/IColumn"; +import axios from "axios"; +import { TickCircle, CloseCircle, InfoCircle } from "iconsax-react"; +import { useNavigate, useParams } from "react-router"; +import SadFace from "../../assets/SadFace.svg"; +import DeadFace from "../../assets/DeadFace.svg"; +import CircularProgress from "@mui/material/CircularProgress"; interface ClubCheckerPageProps { clubId?: number; @@ -48,11 +48,11 @@ interface ClubCheckerPageProps { const ClubCheckerPage = ({ title = "No title selected", // colors - backgroundColor = "#C7CEDF", + backgroundColor = "#ECECEC", titleTextColor = "#000000", - textFieldBackgroundColor = "#E7EBF5", + textFieldBackgroundColor = "#E0E0E0", textFieldTextColor = "#000000", - buttonBackgroundColor = "#A1A8B9", + buttonBackgroundColor = "#C1C1C2", dropDownBackgroundColor = "#4F4F4F", font = "Montserrat", clubLogoUrl, @@ -98,7 +98,7 @@ const ClubCheckerPage = ({ const iconStyle = { color: textFieldTextColor, - } + }; const handleEnterKey = (event: React.KeyboardEvent) => { if (event.key === "Enter") { @@ -120,21 +120,22 @@ const ClubCheckerPage = ({ const response = await axios.get( `/pages/verify/${webLink}/${selectedIdentifier.displayName}/${input}` ); - if (response.data == 'value found in column') { - setIsSuccess('You are already a member of this club!'); + if (response.data == "value found in column") { + setIsSuccess("You are already a member of this club!"); setIconState(1); } else { - setIsSuccess('You are not currently a member of this club!'); + setIsSuccess("You are not currently a member of this club!"); setIconState(2); } } catch (error) { console.error(error); - setIsSuccess('oops! there was an error - please refresh the page and try again.'); + setIsSuccess( + "oops! there was an error - please refresh the page and try again." + ); setIconState(3); } finally { setLoading(false); } - }; const handleFocus = () => { setIconState(0); @@ -144,10 +145,10 @@ const ClubCheckerPage = ({
{title} @@ -168,9 +169,9 @@ const ClubCheckerPage = ({