From cfd7d920db6807498edcd268b55d5b56cbbb40db Mon Sep 17 00:00:00 2001 From: kiel-h-byrne Date: Mon, 26 Jun 2023 10:07:53 -0400 Subject: [PATCH 1/3] feat: Add new BusinessCard component --- components/AppMap.tsx | 7 ++- components/ListingCard.tsx | 66 +++++++++++++++++++++++++ components/ListingCard2.tsx | 85 ++++++++++++++++++++++++++++++++ components/ListingInfoWindow.tsx | 4 +- components/MyMarker.tsx | 17 +++++-- components/SingleInfoContent.tsx | 10 ++-- 6 files changed, 173 insertions(+), 16 deletions(-) create mode 100644 components/ListingCard.tsx create mode 100644 components/ListingCard2.tsx diff --git a/components/AppMap.tsx b/components/AppMap.tsx index f42a5da..a3500fe 100644 --- a/components/AppMap.tsx +++ b/components/AppMap.tsx @@ -10,7 +10,6 @@ import { DrawerHeader, DrawerOverlay, Flex, - Heading, Icon, Tab, TabList, @@ -19,7 +18,7 @@ import { Tabs, Text, useDisclosure, - useToast, + useToast } from "@chakra-ui/react"; import { GoogleMap, @@ -36,6 +35,7 @@ import SWR from "swr"; import { GLocation, IAppMap, IListing } from "../types"; import { CLUSTER_STYLE, GEOCENTER, MAP_STYLES } from "../util/constants"; import { MyInfoWindow, MyMarker } from "./"; +import Card from "./ListingCard"; export const default_props = { center: GEOCENTER, @@ -287,8 +287,7 @@ const AppMap = ({ client_location, setMapInstance, mapInstance }: IAppMap) => { ) : ( - {activeData[0].name} - + )} diff --git a/components/ListingCard.tsx b/components/ListingCard.tsx new file mode 100644 index 0000000..daac71d --- /dev/null +++ b/components/ListingCard.tsx @@ -0,0 +1,66 @@ +import { IListing } from '@/types'; +import { Box, Button, Collapse, Heading, Image, Text } from '@chakra-ui/react'; +import { useState } from 'react'; + +const Card = ({ activeListing }: { activeListing: IListing }) => { + const [isOpen, setIsOpen] = useState(false); + + const toggleCollapse = () => { + setIsOpen(!isOpen); + }; + + const { name, address, description, owner, directions, share, imageUri } = activeListing; + + return ( + + + {name} + + {address} + + {name} + + + {description} + + + + + + {/* Additional owner information */} + + + + + + + + + {/* Additional CTA buttons */} + + + ); +}; + +export default Card; diff --git a/components/ListingCard2.tsx b/components/ListingCard2.tsx new file mode 100644 index 0000000..534b674 --- /dev/null +++ b/components/ListingCard2.tsx @@ -0,0 +1,85 @@ +import { ChevronDownIcon, ChevronUpIcon } from '@chakra-ui/icons'; +import { Box, Button, Collapse, Flex, IconButton, Image, Text } from '@chakra-ui/react'; +import { useState } from 'react'; +import { MdDirections, MdShare } from 'react-icons/md'; + +const BusinessCard = ({ activeListing }) => { + const [isOwnerInfoOpen, setIsOwnerInfoOpen] = useState(false); + const {owner, imageUri } = activeListing + const handleOwnerInfoToggle = () => { + setIsOwnerInfoOpen(!isOwnerInfoOpen); + }; + + return ( + + {/* Image section */} + Business Image + + {/* Business Information */} + + {activeListing} + {owner.name} + {owner.address} + + {/* Owner Information Dropdown */} + + + + : } + aria-label="Toggle Owner Info" + variant="outline" + size="sm" + onClick={handleOwnerInfoToggle} + /> + + + + + Owner Information + {owner.lodge} + {owner.name} + + + + {/* Call to Action Buttons */} + + + + + + + + ); +}; + +export default BusinessCard; diff --git a/components/ListingInfoWindow.tsx b/components/ListingInfoWindow.tsx index 63b4cac..f6ffc8f 100644 --- a/components/ListingInfoWindow.tsx +++ b/components/ListingInfoWindow.tsx @@ -2,7 +2,7 @@ import { Progress } from "@chakra-ui/react"; import { InfoWindow } from "@react-google-maps/api"; import React from "react"; import { IListing } from "../types"; -import { CondensedCard } from "./"; +import ListingCard from "./ListingCard2"; const ListingInfoWindow = ({ activeListing }: {activeListing: IListing}) => { const { lat,lng } = activeListing; @@ -18,7 +18,7 @@ const ListingInfoWindow = ({ activeListing }: {activeListing: IListing}) => { > {activeListing ? (
- +
) : } diff --git a/components/MyMarker.tsx b/components/MyMarker.tsx index b6c3570..44e0e6b 100644 --- a/components/MyMarker.tsx +++ b/components/MyMarker.tsx @@ -29,9 +29,19 @@ const MyMarker = ({ let image = { url: "/img/orange_marker_sm.png", }; - +const mockData = { + name: "Sample Business", + address: "123 Main Street, City", + description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", + owner: { + username: "john_doe", + lodge: "ABC Lodge", + name: "John Doe", + }, imageUri: "https://picsum.photos/200/300", +} const handleMouseOverMarker = () => { - setActiveData([markerData]); + setActiveData([mockData]); + // setActiveData([markerData]); setWindowOpen(); }; const handleMouseOut = () => { @@ -39,7 +49,8 @@ const MyMarker = ({ }; const handleClickMarker = () => { // infowindow needs to be set for mobile (touch, no hover) - setActiveData([markerData]); + setActiveData([mockData]); + // setActiveData([markerData]); toggleDrawer(); }; return ( diff --git a/components/SingleInfoContent.tsx b/components/SingleInfoContent.tsx index ee175da..79ba972 100644 --- a/components/SingleInfoContent.tsx +++ b/components/SingleInfoContent.tsx @@ -1,7 +1,7 @@ -import { Flex, Text } from "@chakra-ui/react"; import { InfoWindow } from "@react-google-maps/api"; import { memo } from "react"; import { IListing } from "../types"; +import Card from "./ListingCard2"; const SingleInfoContent = ({ data, options, @@ -10,15 +10,11 @@ import { IListing } from "../types"; options: any; }) => { const { lat, lng, name } = data[0]; + const listing = data[0] if (lat && lng) { return ( - - {name} - - ---Description---{" "} - - + ); } From bd15425179e61ffff9fba03e160bc9507ea6f69d Mon Sep 17 00:00:00 2001 From: kiel-h-byrne Date: Mon, 28 Aug 2023 00:34:26 -0400 Subject: [PATCH 2/3] some schema changes and debugging listingcard; toast also buggy and considering removing --- components/AppMap.tsx | 47 +++++++++++++++++++-------- components/CustomHead.tsx | 6 ++-- components/ListingCard.tsx | 17 +++++----- components/ListingCard2.tsx | 65 +++++++++++++++++++++++++++---------- db/schemas.ts | 27 +++++---------- types/index.ts | 47 ++++++++++++++++++++------- 6 files changed, 137 insertions(+), 72 deletions(-) diff --git a/components/AppMap.tsx b/components/AppMap.tsx index a3500fe..508f299 100644 --- a/components/AppMap.tsx +++ b/components/AppMap.tsx @@ -11,14 +11,15 @@ import { DrawerOverlay, Flex, Icon, + Progress, Tab, TabList, TabPanel, TabPanels, Tabs, Text, + createStandaloneToast, useDisclosure, - useToast } from "@chakra-ui/react"; import { GoogleMap, @@ -72,7 +73,7 @@ export const default_props = { }, }; -const AppMap = ({ client_location, setMapInstance, mapInstance }: IAppMap) => { +const AppMap = ({ client_location, setMapInstance }: IAppMap) => { let { center, zoom, options } = default_props; const uri = client_location ? `api/listings?lat=${client_location.lat}&lng=${client_location.lng}` @@ -104,7 +105,7 @@ const AppMap = ({ client_location, setMapInstance, mapInstance }: IAppMap) => { errorRetryCount: 2, }); - const toast = useToast(); + const { ToastContainer, toast } = createStandaloneToast(); const useRenderMarkers: (clusterer: Clusterer) => React.ReactElement = useCallback( @@ -180,7 +181,18 @@ const AppMap = ({ client_location, setMapInstance, mapInstance }: IAppMap) => { const handleClickCluster = useCallback(() => { setWindowClosed(); }, [setWindowClosed]); - return isLoaded ? ( + const searchToastData = { + title: "Searching Area...", + status: "loading" as any, + id: "searching-toast", + }; + const noResultsToastData = { + title: "No Results", + status: "info" as any, + id: "noresults-toast", + }; + + return isLoaded ? ( { // const bounds = new window.google.maps.LatLngBounds(); @@ -208,11 +220,9 @@ const AppMap = ({ client_location, setMapInstance, mapInstance }: IAppMap) => { setSelectedCategories={setSelectedCategories} /> )} */} - {!fetchData && toast({ title: "Searching Area...", status: "info" })} - {fetchData && - fetchData.length == 0 && - toast({ title: "No Results", status: "info" })} - {fetchData && fetchData.length !== 0 && ( + {/* */} + {/* {!fetchData && toast(searchToastData)} */} + {fetchData && fetchData.length !== 0 ? ( { > {useRenderMarkers} - )} - + ) : null} + {activeData && isWindowOpen && ( - + )} {activeData && isDrawerOpen && ( @@ -242,7 +255,11 @@ const AppMap = ({ client_location, setMapInstance, mapInstance }: IAppMap) => { - Listing Information + + {" "} + + Listing Information + {activeData.length > 1 ? ( @@ -297,7 +314,9 @@ const AppMap = ({ client_location, setMapInstance, mapInstance }: IAppMap) => { {/* {x.location})} /> */} - ) : null; + ) : ( + + ); }; export default memo(AppMap); diff --git a/components/CustomHead.tsx b/components/CustomHead.tsx index 85ca709..333a4ba 100644 --- a/components/CustomHead.tsx +++ b/components/CustomHead.tsx @@ -66,11 +66,11 @@ const CustomHead = ({ title }: Props) => { name="msapplication-TileImage" content="/img/icons/mstile-144x144.png" /> - + /> */} { ); }; -export default memo(CustomHead) \ No newline at end of file +export default memo(CustomHead); diff --git a/components/ListingCard.tsx b/components/ListingCard.tsx index daac71d..185adff 100644 --- a/components/ListingCard.tsx +++ b/components/ListingCard.tsx @@ -1,6 +1,6 @@ -import { IListing } from '@/types'; -import { Box, Button, Collapse, Heading, Image, Text } from '@chakra-ui/react'; -import { useState } from 'react'; +import { IClaims, IListing } from "@/types"; +import { Box, Button, Collapse, Heading, Image, Text } from "@chakra-ui/react"; +import { useState } from "react"; const Card = ({ activeListing }: { activeListing: IListing }) => { const [isOpen, setIsOpen] = useState(false); @@ -9,8 +9,9 @@ const Card = ({ activeListing }: { activeListing: IListing }) => { setIsOpen(!isOpen); }; - const { name, address, description, owner, directions, share, imageUri } = activeListing; - + const { name, address, description, claims, imageUri } = activeListing; + const getLikelyOwnerInfo = (claims: IClaims) => claims[0]; + const ownerInfo = claims && getLikelyOwnerInfo(claims); return ( { @@ -51,10 +52,10 @@ const Card = ({ activeListing }: { activeListing: IListing }) => { - - {/* Additional CTA buttons */} diff --git a/components/ListingCard2.tsx b/components/ListingCard2.tsx index 534b674..2d4b8b2 100644 --- a/components/ListingCard2.tsx +++ b/components/ListingCard2.tsx @@ -1,11 +1,31 @@ -import { ChevronDownIcon, ChevronUpIcon } from '@chakra-ui/icons'; -import { Box, Button, Collapse, Flex, IconButton, Image, Text } from '@chakra-ui/react'; -import { useState } from 'react'; -import { MdDirections, MdShare } from 'react-icons/md'; +import { IListing, PHA_LODGES } from "@/types"; +import { ChevronDownIcon, ChevronUpIcon } from "@chakra-ui/icons"; +import { + Box, + Button, + Collapse, + Flex, + IconButton, + Image, + Text, +} from "@chakra-ui/react"; +import { useState } from "react"; +import { MdDirections, MdShare } from "react-icons/md"; -const BusinessCard = ({ activeListing }) => { +const getLodgeName = ({ + state, + lodgeNo, +}: { + state: string | undefined; + lodgeNo: number | undefined; + //@ts-ignore +}) => state && lodgeNo && (PHA_LODGES[state] as any[lodgeNo]); + +const BusinessCard = ({ activeListing }: { activeListing: IListing }) => { const [isOwnerInfoOpen, setIsOwnerInfoOpen] = useState(false); - const {owner, imageUri } = activeListing + const { claims, imageUri, creator } = activeListing; + const owner = claims?.[0].member || creator; + const handleOwnerInfoToggle = () => { setIsOwnerInfoOpen(!isOwnerInfoOpen); }; @@ -24,18 +44,20 @@ const BusinessCard = ({ activeListing }) => { {/* Business Information */} - {activeListing} - {owner.name} - {owner.address} + + {activeListing.name} + + + {owner?.name} + + + {activeListing.address} + {/* Owner Information Dropdown */} - { - Owner Information - {owner.lodge} - {owner.name} + + Owner Information + + {owner?.name} + + {getLodgeName({ + state: owner?.profile.lodgeState, + lodgeNo: owner?.profile.lodgeNumber, + })} + diff --git a/db/schemas.ts b/db/schemas.ts index 3548f77..b4ca334 100644 --- a/db/schemas.ts +++ b/db/schemas.ts @@ -1,6 +1,7 @@ import { StatesEnum } from "@/types"; import * as z from "zod"; + const SocialSchema = z.object({ facebook: z.string(), instagram: z.string(), @@ -13,7 +14,6 @@ const ProfileSchema = z.object({ nickName: z.string(), lodgeNumber: z.number(), lodgeState: z.string(), - lodgeName: z.string(), email: z.string().email(), social: SocialSchema, roles: z.array(z.string()), @@ -32,20 +32,13 @@ export const UserSchema = z.object({ }); -const ClaimSchema = z.object({ - ownerId: z.string(), - ownerName: z.string(), - ownerPhone: z.string(), - ownerProofUri: z.string().url(), +export const ClaimSchema = z.object({ + cuid: z.string(), + phone: z.string(), + proofUri: z.string().url(), + member: UserSchema }); -// const OwnerSchema = z.object({ -// id: z.string(), -// name: z.string(), -// phone: z.string(), -// email: z.string().email(), -// }); - export const ListingsSchema = z.object({ name: z.string().min(5), address: z.string(), @@ -56,7 +49,7 @@ export const ListingsSchema = z.object({ country: z.string(), phone: z.string(), url: z.string().url(), - claims: ClaimSchema, + claims: z.array(ClaimSchema), claimsCount: z.number(), lat: z.number(), lng: z.number(), @@ -74,20 +67,18 @@ export const ListingsSchema = z.object({ // email: z.string(), // categories: z.array(z.string()), social: SocialSchema, - creator: z.string(), + creator: UserSchema, submitted: z.date(), }).partial() .transform((data, ctx) => { //make address, and location? and.... - const { street, city, state, zip, lat,lng } = data + const { street, city, state, zip, lat, lng } = data const address = `${street} ${city} ${state} ${zip}` // const geoHash = geohashForLocation([lat, lng]); data["country"] = "USA" data["submitted"] = new Date(); data["address"] = address; // data["geoHash"] = geoHash; - - return data } ); diff --git a/types/index.ts b/types/index.ts index 51940cf..4731b70 100644 --- a/types/index.ts +++ b/types/index.ts @@ -1,14 +1,9 @@ import { STATE_ABBREVIATIONS } from "@/util/constants"; import { GoogleMapProps } from "@react-google-maps/api"; import { z } from "zod"; -import { ListingsSchema, UserSchema } from "../db/schemas"; +import { ClaimSchema, ListingsSchema, UserSchema } from "../db/schemas"; -export interface IClaim { - ownerId?: string; - ownerName?: string; - ownerPhone?: string; - ownerProof?: Date; -} +export type IClaims = z.infer[] export type IListing = z.infer export type IUser = z.infer @@ -22,9 +17,39 @@ export interface IAppMap { mapInstance: GoogleMapProps & any; } export interface ILocateMe { - mapInstance: google.maps.Map | google.maps.StreetViewPanorama; - setClientLocation: any //a usestate fxn returning {latlng}; - clientLocation: GLocation | null + mapInstance: google.maps.Map | google.maps.StreetViewPanorama; + setClientLocation: any //a usestate fxn returning {latlng}; + clientLocation: GLocation | null } export interface GLocation { lat: number, lng: number } -export const StatesEnum = z.enum(STATE_ABBREVIATIONS) \ No newline at end of file +export const StatesEnum = z.enum(STATE_ABBREVIATIONS) + +export const PHA_LODGES = { + [StatesEnum.enum.DC]: { + 1: "Social", + 3: "Felix", + 4: "Hiram", + 5: "Eureka", + 6: "Meridian", + 7: "Widow's Son", + 8: "Warren", + 9: "Pythagoras", + 10: "John F. Cook", + 12: "St. John's", + 14: "Prince Hall", + 15: "Charles Datcher", + 16: "James H. Hill", + 17: "Ionic", + 18: "Corinthian", + 19: "Doric", + 20: "Fidelity", + 22: "Harmony", + 23: "Victory", + 24: "Redemption", + 25: "Acacia", + 26: "Fellowship", + 27: "Prudence", + 28: "Thomas L. Johnson", + 29: "Nathaniel M. Adams Jr. Military", + } +} \ No newline at end of file From 67ecd9b9ed82891e208283739f8539f5842b24a3 Mon Sep 17 00:00:00 2001 From: kiel-h-byrne Date: Fri, 13 Oct 2023 16:49:33 -0400 Subject: [PATCH 3/3] Fix UI rendering issue when switching between map and list view --- components/AddListingForm.tsx | 9 ++------- components/AppList.tsx | 21 +++++++++++++++++++++ components/AppMap.tsx | 4 ++-- components/ListingCard.tsx | 5 ++--- next.config.js | 2 ++ pages/_document.tsx | 4 ++-- pages/index.tsx | 17 +++++++++++++---- tsconfig.json | 34 ++++++++++++++++++++++++++++------ 8 files changed, 72 insertions(+), 24 deletions(-) create mode 100644 components/AppList.tsx diff --git a/components/AddListingForm.tsx b/components/AddListingForm.tsx index bb0a4c9..04d9bf4 100644 --- a/components/AddListingForm.tsx +++ b/components/AddListingForm.tsx @@ -99,13 +99,7 @@ const AddListingForm = ({ onDrawerClose }: { onDrawerClose: () => void }) => { ); useEffect(() => { - if (Object.keys(errors).length !== 0) { - console.log(errors); - } - }, [errors]); - - useEffect(() => { - isSubmitting && submitToast(); + isSubmitting && Object.keys(errors).length !==0 && submitToast(); if (isSubmitSuccessful) { reset(); onDrawerClose(); @@ -118,6 +112,7 @@ const AddListingForm = ({ onDrawerClose }: { onDrawerClose: () => void }) => { reset, onDrawerClose, successToast, + errors ]); return ( diff --git a/components/AppList.tsx b/components/AppList.tsx new file mode 100644 index 0000000..3bf3625 --- /dev/null +++ b/components/AppList.tsx @@ -0,0 +1,21 @@ +import { IListing } from "@/types"; +import fetcher from "@/util/fetch"; +import { HStack } from '@chakra-ui/react'; +import SWR from "swr"; +import BusinessCard from "./ListingCard2"; +const AppList = () => { + const data_uri = "api/listings"; + const { data: fetchData, error } = SWR(data_uri, fetcher, { + loadingTimeout: 1000, + errorRetryCount: 2, + }); + return ( + + {fetchData && fetchData.map((listing: IListing) => + + )} + + ); +}; + +export default AppList; diff --git a/components/AppMap.tsx b/components/AppMap.tsx index 508f299..ba2ce6e 100644 --- a/components/AppMap.tsx +++ b/components/AppMap.tsx @@ -36,7 +36,7 @@ import SWR from "swr"; import { GLocation, IAppMap, IListing } from "../types"; import { CLUSTER_STYLE, GEOCENTER, MAP_STYLES } from "../util/constants"; import { MyInfoWindow, MyMarker } from "./"; -import Card from "./ListingCard"; +import ListingCard from "./ListingCard"; export const default_props = { center: GEOCENTER, @@ -304,7 +304,7 @@ const AppMap = ({ client_location, setMapInstance }: IAppMap) => { ) : ( - + )} diff --git a/components/ListingCard.tsx b/components/ListingCard.tsx index 185adff..dd53338 100644 --- a/components/ListingCard.tsx +++ b/components/ListingCard.tsx @@ -2,9 +2,8 @@ import { IClaims, IListing } from "@/types"; import { Box, Button, Collapse, Heading, Image, Text } from "@chakra-ui/react"; import { useState } from "react"; -const Card = ({ activeListing }: { activeListing: IListing }) => { +const ListingCard = ({ activeListing }: { activeListing: IListing }) => { const [isOpen, setIsOpen] = useState(false); - const toggleCollapse = () => { setIsOpen(!isOpen); }; @@ -64,4 +63,4 @@ const Card = ({ activeListing }: { activeListing: IListing }) => { ); }; -export default Card; +export default ListingCard; diff --git a/next.config.js b/next.config.js index 70ba11c..5e40d41 100644 --- a/next.config.js +++ b/next.config.js @@ -1,3 +1,5 @@ +// @ts-check + /** @type {import('next').NextConfig} */ const nextConfig = { reactStrictMode: true, diff --git a/pages/_document.tsx b/pages/_document.tsx index 5617e9e..0cd6e66 100644 --- a/pages/_document.tsx +++ b/pages/_document.tsx @@ -1,12 +1,12 @@ -import NextDocument, { Html, Head, Main, NextScript } from "next/document"; import { ColorModeScript } from "@chakra-ui/react"; +import NextDocument, { Head, Html, Main, NextScript } from "next/document"; import { chakraTheme } from "../chakra-theme"; export default class Document extends NextDocument { render() { return ( - + { const [clientLocation, setClientLocation] = useState(null); const [mapInstance, setMapInstance] = useState({} as google.maps.Map); +// type VIEW_TYPE = 'map' | 'list' + const params = useSearchParams() +const viewType = params?.get('viewType') return ( <> + {viewType === 'map' ? <> + /> + + : + } ); diff --git a/tsconfig.json b/tsconfig.json index e49c388..1b0cf06 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,11 @@ { "compilerOptions": { "target": "es5", - "lib": ["dom", "dom.iterable", "esnext"], + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], "allowJs": true, "skipLibCheck": true, "strict": true, @@ -16,11 +20,29 @@ "incremental": true, "baseUrl": ".", "paths": { - "@/*": ["./*"], + "@/*": [ + "./*" + ] }, - "types": ["jest", "node", "@testing-library/jest-dom"] - + "types": [ + "jest", + "node", + "@testing-library/jest-dom" + ], + "plugins": [ + { + "name": "next" + } + ] }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "types.d.ts"], - "exclude": ["node_modules"] + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + "types.d.ts", + ".next/types/**/*.ts" + ], + "exclude": [ + "node_modules" + ] }