From 58f8837211d814b9d994e9cb488589c59d1dd21e Mon Sep 17 00:00:00 2001 From: John Eric Date: Fri, 30 Aug 2024 15:02:05 +0800 Subject: [PATCH] chore: code optimisations --- src/components/modal/congoptions.tsx | 41 +----- src/components/modal/newprivateadd.tsx | 7 +- src/components/modal/newpublicadd.tsx | 7 +- src/components/modal/newterritorycd.tsx | 9 +- src/components/navigation/territorylist.tsx | 2 +- src/components/table/admin.tsx | 5 +- src/components/table/privatetable.tsx | 3 +- src/components/table/publictable.tsx | 3 +- src/pages/admin.tsx | 146 +++++++++----------- src/pages/slip.tsx | 56 ++++---- src/utils/constants.tsx | 8 +- src/utils/helpers/checkcongexp.ts | 11 -- src/utils/helpers/checkmaxtries.ts | 11 -- src/utils/helpers/getcongoptions.ts | 22 ++- src/utils/helpers/getterritorydetails.ts | 48 +++---- 15 files changed, 176 insertions(+), 203 deletions(-) delete mode 100644 src/utils/helpers/checkcongexp.ts delete mode 100644 src/utils/helpers/checkmaxtries.ts diff --git a/src/components/modal/congoptions.tsx b/src/components/modal/congoptions.tsx index 16ee6834..3943e8b2 100644 --- a/src/components/modal/congoptions.tsx +++ b/src/components/modal/congoptions.tsx @@ -1,13 +1,6 @@ import NiceModal, { useModal, bootstrapDialog } from "@ebay/nice-modal-react"; import { useRollbar } from "@rollbar/react"; -import { - set, - ref, - get, - query, - orderByChild, - DataSnapshot -} from "firebase/database"; +import { set, ref } from "firebase/database"; import { useState, FormEvent, @@ -35,12 +28,12 @@ import { HHOptionProps, UpdateCongregationOptionsModalProps } from "../../utils/interface"; -import pollingQueryFunction from "../../utils/helpers/pollingquery"; import GenericInputField from "../form/input"; import ModalSubmitButton from "../form/submit"; import { confirmAlert } from "react-confirm-alert"; import { flushSync } from "react-dom"; import { usePostHog } from "posthog-js/react"; +import { getOptions } from "../../utils/helpers/getcongoptions"; const UpdateCongregationOptions = NiceModal.create( ({ currentCongregation }: UpdateCongregationOptionsModalProps) => { @@ -184,38 +177,16 @@ const UpdateCongregationOptions = NiceModal.create( ); useEffect(() => { - const getOptions = async () => { + const getHHOptions = async () => { try { - const optionsSnapshot = await pollingQueryFunction(() => - get( - query( - ref( - database, - `congregations/${currentCongregation}/options/list` - ), - orderByChild("sequence") - ) - ) - ); - const optionValues: Array = []; - optionsSnapshot.forEach((element: DataSnapshot) => { - const optionDetails = element.val(); - const optionCode = element.key as string; - const option = { - code: optionCode, - description: optionDetails.description, - isCountable: optionDetails.isCountable || false, - isDefault: optionDetails.isDefault || false, - sequence: optionDetails.sequence - }; - optionValues.push(option); - }); + const optionValues: Array = + await getOptions(currentCongregation); setOptions(optionValues); } catch (error) { errorHandler(error, rollbar); } }; - getOptions(); + getHHOptions(); }, [currentCongregation]); return ( diff --git a/src/components/modal/newprivateadd.tsx b/src/components/modal/newprivateadd.tsx index b5fdd36c..eaca6cc2 100644 --- a/src/components/modal/newprivateadd.tsx +++ b/src/components/modal/newprivateadd.tsx @@ -8,7 +8,8 @@ import { TERRITORY_TYPES, STATUS_CODES, NOT_HOME_STATUS_CODES, - WIKI_CATEGORIES + WIKI_CATEGORIES, + DEFAULT_AGGREGATES } from "../../utils/constants"; import isValidPostal from "../../utils/helpers/checkvalidpostal"; import isValidPostalSequence from "../../utils/helpers/checkvalidseq"; @@ -112,7 +113,9 @@ const NewPrivateAddress = NiceModal.create( location: location, units: floorDetails, type: TERRITORY_TYPES.PRIVATE, - coordinates: coordinates + coordinates: coordinates, + aggregates: DEFAULT_AGGREGATES, + delta: 0 }) ); posthog?.capture("create_private_address", { diff --git a/src/components/modal/newpublicadd.tsx b/src/components/modal/newpublicadd.tsx index dbf9244d..3cc08a72 100644 --- a/src/components/modal/newpublicadd.tsx +++ b/src/components/modal/newpublicadd.tsx @@ -9,7 +9,8 @@ import { TERRITORY_TYPES, STATUS_CODES, NOT_HOME_STATUS_CODES, - WIKI_CATEGORIES + WIKI_CATEGORIES, + DEFAULT_AGGREGATES } from "../../utils/constants"; import isValidPostal from "../../utils/helpers/checkvalidpostal"; import isValidPostalSequence from "../../utils/helpers/checkvalidseq"; @@ -116,7 +117,9 @@ const NewPublicAddress = NiceModal.create( units: floorDetails, type: TERRITORY_TYPES.PUBLIC, location: location, - coordinates: coordinates + coordinates: coordinates, + aggregates: DEFAULT_AGGREGATES, + delta: 0 }) ); posthog?.capture("create_public_address", { diff --git a/src/components/modal/newterritorycd.tsx b/src/components/modal/newterritorycd.tsx index 83abe5d5..da4fd009 100644 --- a/src/components/modal/newterritorycd.tsx +++ b/src/components/modal/newterritorycd.tsx @@ -4,7 +4,11 @@ import { child, ref, get, set } from "firebase/database"; import { useState, FormEvent, ChangeEvent } from "react"; import { Modal, Form } from "react-bootstrap"; import { database } from "../../firebase"; -import { USER_ACCESS_LEVELS, WIKI_CATEGORIES } from "../../utils/constants"; +import { + DEFAULT_AGGREGATES, + USER_ACCESS_LEVELS, + WIKI_CATEGORIES +} from "../../utils/constants"; import pollingVoidFunction from "../../utils/helpers/pollingvoid"; import errorHandler from "../../utils/helpers/errorhandler"; import pollingQueryFunction from "../../utils/helpers/pollingquery"; @@ -45,7 +49,8 @@ const NewTerritoryCode = NiceModal.create( } await pollingVoidFunction(() => set(territoryCodeReference, { - name: name + name: name, + aggregates: DEFAULT_AGGREGATES }) ); posthog?.capture("create_territory", { diff --git a/src/components/navigation/territorylist.tsx b/src/components/navigation/territorylist.tsx index ec059e59..0ea500f5 100644 --- a/src/components/navigation/territorylist.tsx +++ b/src/components/navigation/territorylist.tsx @@ -40,7 +40,7 @@ const TerritoryListing = memo( className="d-flex justify-content-between align-items-start" > <> - {element.code} - {element.name} ({element.aggregates}) + {element.code} - {element.name} diff --git a/src/components/table/publictable.tsx b/src/components/table/publictable.tsx index f2fa03ca..3420faa9 100644 --- a/src/components/table/publictable.tsx +++ b/src/components/table/publictable.tsx @@ -3,6 +3,7 @@ import { territoryTableProps } from "../../utils/interface"; import TableHeader from "./header"; import FloorHeader from "./floor"; import UnitStatus from "./unit"; +import { DEFAULT_AGGREGATES } from "../../utils/constants"; const PublicTerritoryTable = ({ postalCode, floors, @@ -29,7 +30,7 @@ const PublicTerritoryTable = ({ >([]); const [selectedTerritoryCode, setSelectedTerritoryCode] = useState(); const [selectedTerritoryName, setSelectedTerritoryName] = useState(); - const [selectedTerritoryAggregates, setSelectedTerritoryAggregates] = - useState(0); const [addressData, setAddressData] = useState( new Map() ); @@ -286,17 +280,16 @@ function Admin({ user }: adminProps) { const processSelectedTerritory = async (selectedTerritoryCode: string) => { try { - const { territoryAddsResult, territoryNameResult, territoryAggregates } = - await getTerritoryData(code, selectedTerritoryCode); - setSelectedTerritoryCode(selectedTerritoryCode); - setSelectedTerritoryName(territoryNameResult.val()); - setSelectedTerritoryAggregates( - territoryAggregates.exists() ? territoryAggregates.val().value : 0 + const territoryAddsResult = await getTerritoryData( + code, + selectedTerritoryCode ); - + setSelectedTerritoryCode(selectedTerritoryCode); + setSelectedTerritoryName(territories.get(selectedTerritoryCode)?.name); refreshAddressState(); unsubscribers.current = [] as Array; + if (!territoryAddsResult) return; const detailsListing = getDetailsListing(territoryAddsResult); setSortedAddressList(detailsListing); @@ -716,15 +709,12 @@ function Admin({ user }: adminProps) { }; const processCongregationTerritories = ( - snapshot: DataSnapshot | undefined + // eslint-disable-next-line @typescript-eslint/no-explicit-any + congregationTerritories: any ) => { + const territoryList = new Map(); try { - if (!snapshot) return; - const data = snapshot.val(); - if (!data) return; - document.title = data["name"] as string; - const congregationTerritories = data["territories"]; - const territoryList = new Map(); + if (!congregationTerritories) return territoryList; for (const territory in congregationTerritories) { const name = congregationTerritories[territory]["name"]; const addresses = congregationTerritories[territory]["addresses"]; @@ -737,15 +727,10 @@ function Admin({ user }: adminProps) { aggregates: aggregates }); } - setTerritories(territoryList); - setName(data["name"] as string); - return territoryList; } catch (error) { console.error("Error processing congregation territories: ", error); } - }; - const getUserAccessLevel = async (congregationCode: string) => { - return congregationAccess.current[congregationCode]; + return territoryList; }; const handleTerritorySelect = useCallback( @@ -934,63 +919,65 @@ function Admin({ user }: adminProps) { if (!code) return; refreshAddressState(); - Promise.all([ - getUserAccessLevel(code), - checkCongregationExpireHours(code), - checkCongregationMaxTries(code), - getOptions(code), - getOptionIsMultiSelect(code), - getCongregationDetails(code), - getCongregationOrigin(code) - ]) - .then( - ([ - userAccessLevel, - expireHours, - maxTries, - options, - optionIsMultiselect, - congregationDetails, - origin - ]) => { - setUserAccessLevel(Number(userAccessLevel)); - setDefaultExpiryHours( - expireHours.exists() - ? expireHours.val() - : DEFAULT_SELF_DESTRUCT_HOURS + setUserAccessLevel(congregationAccess.current[code]); + const congregationUnsub = onValue( + child(ref(database), `congregations/${code}`), + (snapshot) => { + try { + if (!snapshot.exists()) { + setIsUnauthorised(true); + errorHandler( + `Unauthorised access by ${user.email}`, + rollbar, + false + ); + return; + } + const congregationDetails = snapshot.val(); + const congName = congregationDetails["name"] as string; + const expireHours = + congregationDetails["expireHours"] || DEFAULT_SELF_DESTRUCT_HOURS; + const maxTries = + congregationDetails["maxTries"] || DEFAULT_CONGREGATION_MAX_TRIES; + const options = processOptions( + congregationDetails["options"]["list"] ); + const optionIsMultiselect = + congregationDetails["options"]["isMultiselect"] || + DEFAULT_CONGREGATION_OPTION_IS_MULTIPLE; + const origin = + congregationDetails["origin"] || + DEFAULT_MAP_DIRECTION_CONGREGATION_LOCATION; + const congregationTerritories = processCongregationTerritories( + congregationDetails["territories"] + ); + + document.title = congName; + setName(congName); + setDefaultExpiryHours(expireHours); setOptions(options); setPolicy( new Policy( loginUserClaims.current, options, - maxTries.exists() - ? maxTries.val() - : DEFAULT_CONGREGATION_MAX_TRIES, - optionIsMultiselect.exists() - ? optionIsMultiselect.val() - : DEFAULT_CONGREGATION_OPTION_IS_MULTIPLE, - origin.exists() - ? origin.val() - : DEFAULT_MAP_DIRECTION_CONGREGATION_LOCATION + maxTries, + optionIsMultiselect, + origin ) ); - + setTerritories(congregationTerritories); posthog?.identify(code, { - name: congregationDetails.exists() - ? congregationDetails.val()["name"] - : "" + name: congName }); - processCongregationTerritories( - congregationDetails.exists() ? congregationDetails : undefined - ); + } catch (error) { + errorHandler(error, rollbar); + } finally { setIsLoading(false); } - ) - .catch((error) => { - // Handle the error here - console.error(error); - }); + } + ); + + return () => congregationUnsub(); }, [code]); if (isLoading) return ; @@ -1068,7 +1055,10 @@ function Admin({ user }: adminProps) { {selectedTerritoryCode ? ( <> {selectedTerritoryCode} @@ -1480,8 +1470,10 @@ function Admin({ user }: adminProps) { if (!addressElement) return
; const currentPostalname = addressElement.name; - const completeValue = addressElement.aggregates.value; - const completedPercent = addressElement.aggregates.display; + const completeValue = + addressElement.aggregates?.value || DEFAULT_AGGREGATES.value; + const completedPercent = + addressElement.aggregates?.display || DEFAULT_AGGREGATES.display; const assigneeCount = addressElement.assigneeDetailsList.length; const personalCount = addressElement.personalDetailsList.length; const maxUnitNumberLength = addressElement.maxUnitLength; diff --git a/src/pages/slip.tsx b/src/pages/slip.tsx index 2aa8ad1d..0d224f29 100644 --- a/src/pages/slip.tsx +++ b/src/pages/slip.tsx @@ -14,7 +14,6 @@ import { LinkSession, Policy } from "../utils/policies"; import ZeroPad from "../utils/helpers/zeropad"; import processAddressData from "../utils/helpers/processadddata"; import getMaxUnitLength from "../utils/helpers/maxunitlength"; -import getOptions from "../utils/helpers/getcongoptions"; import Legend from "../components/navigation/legend"; import Loader from "../components/statics/loader"; import { @@ -35,13 +34,13 @@ import InstructionImg from "../assets/instruction.svg?react"; import TimeImg from "../assets/time.svg?react"; import ModalManager from "@ebay/nice-modal-react"; import GetDirection from "../utils/helpers/directiongenerator"; -import getOptionIsMultiSelect from "../utils/helpers/getoptionmultiselect"; -import getCongregationOrigin from "../utils/helpers/getcongorigin"; import { useParams } from "react-router-dom"; import InvalidPage from "../components/statics/invalidpage"; import { useRollbar } from "@rollbar/react"; import SuspenseComponent from "../components/utils/suspense"; import { usePostHog } from "posthog-js/react"; +import { processOptions } from "../utils/helpers/getcongoptions"; +import getCongregationDetails from "../utils/helpers/getcongdetails"; const UpdateUnitStatus = lazy(() => import("../components/modal/updatestatus")); @@ -58,9 +57,6 @@ const Map = () => { const [isLinkExpired, setIsLinkExpired] = useState(true); const [tokenEndTime, setTokenEndTime] = useState(0); const [publisherName, setPublisherName] = useState(""); - const [congregationMaxTries, setCongregationMaxTries] = useState( - DEFAULT_CONGREGATION_MAX_TRIES - ); const [postalcode, setPostalcode] = useState(""); const [showLegend, setShowLegend] = useState(false); @@ -131,7 +127,6 @@ const Map = () => { const tokenEndtime = linkrec.tokenEndtime; setPublisherName(linkrec.publisherName); - setCongregationMaxTries(linkrec.maxTries); setPostalcode(linkrec.postalCode); const currentTimestamp = new Date().getTime(); setTokenEndTime(tokenEndtime); @@ -164,27 +159,37 @@ const Map = () => { useEffect(() => { const getMapData = async () => { if (!code || !postalcode) return; - const options = await getOptions(code); - const isMultiselect = await getOptionIsMultiSelect(code); - const origin = await getCongregationOrigin(code); + const congregationDetails = await getCongregationDetails(code); + if (!congregationDetails.exists()) { + setIsLoading(false); + return; + } + const congregationData = congregationDetails.val(); + const options = processOptions(congregationData.options?.list); + const isMultiselect = + congregationData.options?.isMultiSelect || + DEFAULT_CONGREGATION_OPTION_IS_MULTIPLE; + const origin = + congregationData.origin || DEFAULT_MAP_DIRECTION_CONGREGATION_LOCATION; + const congregationMaxTries = + congregationData.maxTries || DEFAULT_CONGREGATION_MAX_TRIES; setOptions(options); setPolicy( new Policy( undefined, options, congregationMaxTries, - isMultiselect.exists() - ? isMultiselect.val() - : DEFAULT_CONGREGATION_OPTION_IS_MULTIPLE, - origin.exists() - ? origin.val() - : DEFAULT_MAP_DIRECTION_CONGREGATION_LOCATION + isMultiselect, + origin ) ); onValue( child(ref(database), `addresses/${code}/${postalcode}`), - (snapshot) => { - if (snapshot.exists()) { + async (snapshot) => { + try { + if (!snapshot.exists()) { + return; + } const postalSnapshot = snapshot.val(); setValues((values) => ({ ...values, @@ -197,14 +202,15 @@ const Map = () => { postalSnapshot.coordinates || DEFAULT_COORDINATES.Singapore ); setAggregate(postalSnapshot.aggregates); - processAddressData(code, postalcode, postalSnapshot.units) - .then((data) => { - setFloors(data); - }) - .finally(() => { - setIsLoading(false); - }); + const data = await processAddressData( + code, + postalcode, + postalSnapshot.units + ); + setFloors(data); document.title = postalSnapshot.name; + } finally { + setIsLoading(false); } } ); diff --git a/src/utils/constants.tsx b/src/utils/constants.tsx index ef9a5643..b2debf36 100644 --- a/src/utils/constants.tsx +++ b/src/utils/constants.tsx @@ -97,6 +97,11 @@ const NOTIFICATION_TYPES = { INSTRUCTIONS: 2 }; +const DEFAULT_AGGREGATES = { + value: 0, + display: "0%" +}; + //eslint-disable-next-line const SPECIAL_CHARACTERS = /[`!@#$%^&()_+\=\[\]{};':"\\|,.<>\/?~][^-*]/; const NUMERIC_CHARACTERS = /^-?\d+$/; @@ -324,5 +329,6 @@ export { DEFAULT_COORDINATES, CLOUD_FUNCTIONS_CALLS, AI_SETTINGS, - PH_STATUS_KEYS + PH_STATUS_KEYS, + DEFAULT_AGGREGATES }; diff --git a/src/utils/helpers/checkcongexp.ts b/src/utils/helpers/checkcongexp.ts deleted file mode 100644 index 67e38e0b..00000000 --- a/src/utils/helpers/checkcongexp.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { get, child, ref } from "firebase/database"; -import { database } from "../../firebase"; -import pollingQueryFunction from "./pollingquery"; - -const checkCongregationExpireHours = async (code: string) => { - return await pollingQueryFunction(() => - get(child(ref(database), `congregations/${code}/expiryHours`)) - ); -}; - -export default checkCongregationExpireHours; diff --git a/src/utils/helpers/checkmaxtries.ts b/src/utils/helpers/checkmaxtries.ts deleted file mode 100644 index 073333f6..00000000 --- a/src/utils/helpers/checkmaxtries.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { get, child, ref } from "firebase/database"; -import { database } from "../../firebase"; -import pollingQueryFunction from "./pollingquery"; - -const checkCongregationMaxTries = async (code: string) => { - return await pollingQueryFunction(() => - get(child(ref(database), `congregations/${code}/maxTries`)) - ); -}; - -export default checkCongregationMaxTries; diff --git a/src/utils/helpers/getcongoptions.ts b/src/utils/helpers/getcongoptions.ts index 9db0860f..37f817a4 100644 --- a/src/utils/helpers/getcongoptions.ts +++ b/src/utils/helpers/getcongoptions.ts @@ -28,4 +28,24 @@ const getOptions = async (code: string) => { return householdTypes; }; -export default getOptions; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const processOptions = (optionList: any) => { + const householdTypes = new Array(); + + // Retrieve the household types from the snapshot + Object.keys(optionList).forEach((key) => { + const value = optionList[key]; + householdTypes.push({ + code: key, + description: value.description, + isCountable: value.isCountable, + isDefault: value.isDefault, + sequence: value.sequence + }); + }); + // Sort the household types by sequence + householdTypes.sort((a, b) => a.sequence - b.sequence); + return householdTypes; +}; + +export { getOptions, processOptions }; diff --git a/src/utils/helpers/getterritorydetails.ts b/src/utils/helpers/getterritorydetails.ts index 1817ce16..10e251fa 100644 --- a/src/utils/helpers/getterritorydetails.ts +++ b/src/utils/helpers/getterritorydetails.ts @@ -1,4 +1,4 @@ -import { get, query, ref, orderByValue, child } from "firebase/database"; +import { get, query, ref, orderByValue } from "firebase/database"; import { database } from "../../firebase"; import pollingQueryFunction from "./pollingquery"; @@ -6,38 +6,24 @@ const getTerritoryData = async ( code: string, selectedTerritoryCode: string ) => { - const [territoryAddsResult, territoryNameResult, territoryAggregates] = - await Promise.all([ - pollingQueryFunction(() => - get( - query( - ref( - database, - `congregations/${code}/territories/${selectedTerritoryCode}/addresses` - ), - orderByValue() - ) - ) + try { + const territoryRef = query( + ref( + database, + `congregations/${code}/territories/${selectedTerritoryCode}/addresses` ), - pollingQueryFunction(() => - get( - child( - ref(database), - `congregations/${code}/territories/${selectedTerritoryCode}/name` - ) - ) - ), - pollingQueryFunction(() => - get( - child( - ref(database), - `congregations/${code}/territories/${selectedTerritoryCode}/aggregates` - ) - ) - ) - ]); + orderByValue() + ); + + const territoryAddsResult = await pollingQueryFunction(() => + get(territoryRef) + ); - return { territoryAddsResult, territoryNameResult, territoryAggregates }; + return territoryAddsResult; + } catch (error) { + console.error("Error fetching territory data:", error); + return; + } }; export default getTerritoryData;