diff --git a/src/components/collapsible/index.tsx b/src/components/collapsible/index.tsx index 9dfaa43..80d5977 100644 --- a/src/components/collapsible/index.tsx +++ b/src/components/collapsible/index.tsx @@ -1,7 +1,8 @@ import React from "react"; import { useState, useRef } from "react"; -import './collapsible.css'; +import "./collapsible.css"; import { FaAngleDown, FaAngleUp } from "react-icons/fa"; +import { Collapse } from "react-bootstrap"; //This is collapsible component, use it as if you are using any pre-designed component //Specify the Style of collapsible component as if you were styling a div using style prompt @@ -49,8 +50,8 @@ const Collapsible = (props: PropTypes) => { style={{ height: isOpen ? `fit-content` : '0px' }}>
{props.children}
- - ) -} + + ); +}; export default Collapsible; diff --git a/src/components/dashboard/AddProvider.tsx b/src/components/dashboard/AddProvider.tsx index 6dfa60d..73ba6a3 100644 --- a/src/components/dashboard/AddProvider.tsx +++ b/src/components/dashboard/AddProvider.tsx @@ -4,7 +4,7 @@ import React, { useState, useEffect } from "react"; import Steps, { Step } from "rc-steps"; import "rc-steps/assets/index.css"; import "rc-steps/assets/iconfont.css"; -import 'bootstrap/dist/css/bootstrap.min.css'; +import "bootstrap/dist/css/bootstrap.min.css"; import Form from "react-bootstrap/Form"; import Row from "react-bootstrap/Row"; import Col from "react-bootstrap/Col"; @@ -27,8 +27,6 @@ import { storage } from "../../store"; import { Store } from "reducers/types"; const { v4: uuidv4 } = require("uuid"); -import { SimpleEditor } from "./TextComponent/SimpleEditor"; - let steps = [ "Map", "Hours", @@ -50,7 +48,9 @@ function AddProvider(props) { const [descriptions, setDescriptions] = useState(null); const [single, setSingle] = useState(null); const [error, setError] = useState(""); - const [content, setContent] = useState('ex. "Changing lives one bit at a time..."'); + const [content, setContent] = useState( + 'ex. "Changing lives one bit at a time..."' + ); const handleUpdate = (updatedContent: string) => { setContent(updatedContent); }; @@ -115,7 +115,6 @@ function AddProvider(props) { useEffect(() => { function updateSteps() { - console.log(filters) if (filters && !Object.keys(filters).length) { const delIndex = steps.indexOf("Tag"); delIndex !== -1 && steps.splice(delIndex, 1); @@ -140,7 +139,7 @@ function AddProvider(props) { const delIndex = steps.indexOf("Toggle"); delIndex !== -1 && steps.splice(delIndex, 1); } - + if (single && Object.keys(single).length) { const delIndex = steps.indexOf("Toggle"); delIndex == -1 && steps.push("Toggle"); @@ -149,22 +148,51 @@ function AddProvider(props) { updateSteps(); }, [filters, descriptions, single]); - // function updateSteps() { - // if (filters && !Object.keys(filters).length) { - // const delIndex = steps.indexOf("Tag"); - // delIndex !== -1 && steps.splice(delIndex, 1); - // } - - // if (descriptions && !Object.keys(descriptions).length) { - // const delIndex = steps.indexOf("Text"); - // delIndex !== -1 && steps.splice(delIndex, 1); - // } + const validateComponents = (i) => { + if (!i.content) { + return true; + } + const components = (i.content?.sections ?? []).flatMap( + (section) => section.components + ); + return components.every((component) => { + return validateComponent(component); + }); + }; - // if (categories && !Object.keys(categories).length) { - // const delIndex = steps.indexOf("Toggle"); - // delIndex !== -1 && steps.splice(delIndex, 1); - // } - // } + const validateComponent = (component) => { + const { type, data } = component; + switch (type) { + case "Chart": + switch (data.type) { + case "donut": + return !!(data.data.donutData?.length > 0); + case "progress": + return ( + data.data.current != null && + !isNaN(data.data.current) && + data.data.total != null && + !isNaN(data.data.total) + ); + case "line": + return !!(data.data.lineData?.length > 0); + default: + return true; + } + case "Gallery": + return data.slidesArray.every((slide) => { + return slide.title !== ""; + }); + case "Directory": + return data.items.every((item) => { + return item.name !== ""; + }); + case "Embed": + return data.embedLink !== ""; + default: + return true; + } + }; async function addFirestore() { setIsLoading(true); @@ -182,9 +210,9 @@ function AddProvider(props) { fetch( `https://maps.googleapis.com/maps/api/geocode/json?address=${i.address[0].replace( /\s/g, - "%20", - )}&key=${GOOGLE_API_KEY}`, - ), + "%20" + )}&key=${GOOGLE_API_KEY}` + ) ); const responseJson = await response.json(); if ( @@ -196,7 +224,7 @@ function AddProvider(props) { } if (!i.imageURL) { const res = await fetch( - `https://maps.googleapis.com/maps/api/streetview?size=500x500&location=${i.latitude},${i.longitude}&fov=80&heading=70&pitch=0&key=${GOOGLE_API_KEY}`, + `https://maps.googleapis.com/maps/api/streetview?size=500x500&location=${i.latitude},${i.longitude}&fov=80&heading=70&pitch=0&key=${GOOGLE_API_KEY}` ); const blob = await res.blob(); const filename = i.facilityName + ".jpeg"; @@ -212,15 +240,15 @@ function AddProvider(props) { } await promiseWithTimeout( 5000, - props.firestore.set( - { collection: "providers", doc: i.id }, - i, - ), + props.firestore.set({ + collection: "providers", + doc: i.id + }, i) ); props.history.push(providerRoute); } catch (e) { setError( - "Failed to save changes. Please check your network connection or try again later.", + "Failed to save changes. Please check your network connection or try again later." ); } finally { setIsLoading(false); @@ -239,8 +267,8 @@ function AddProvider(props) { const response = await fetch( `https://maps.googleapis.com/maps/api/geocode/json?address=${i.address[0].replace( /\s/g, - "%20", - )}&key=${GOOGLE_API_KEY}`, + "%20" + )}&key=${GOOGLE_API_KEY}` ); const responseJson = await response.json(); if ( @@ -252,7 +280,7 @@ function AddProvider(props) { } if (!i.imageURL) { const res = await fetch( - `https://maps.googleapis.com/maps/api/streetview?size=500x500&location=${i.latitude},${i.longitude}&fov=80&heading=70&pitch=0&key=${GOOGLE_API_KEY}`, + `https://maps.googleapis.com/maps/api/streetview?size=500x500&location=${i.latitude},${i.longitude}&fov=80&heading=70&pitch=0&key=${GOOGLE_API_KEY}` ); const blob = await res.blob(); const filename = i.facilityName + ".jpeg"; @@ -274,7 +302,7 @@ function AddProvider(props) { querySnapshot.forEach((doc) => { firestore.update( { collection: "providers", doc: doc.id }, - i, + i ); }); }); @@ -282,7 +310,7 @@ function AddProvider(props) { props.history.push(providerRoute); } catch (e) { setError( - "Failed to save changes. Please check your network connection or try again later.", + "Failed to save changes. Please check your network connection or try again later." ); } finally { setIsLoading(false); @@ -343,13 +371,13 @@ function AddProvider(props) { disabled={!completed} onClick={ props.selected && - props.selected.facilityName + props.selected.facilityName ? updateFirestore : addFirestore } > {props.selected && - props.selected.facilityName + props.selected.facilityName ? "Edit" : "Add"}{" "} Provider @@ -366,7 +394,12 @@ function AddProvider(props) { )} - +
@@ -389,10 +422,10 @@ function AddProvider(props) { - {components.map((v, i) => + {components.map((v, i) => ( - {v} + + {switchRender(v.type, v.data, i)} + - )} - + ))} + + }} + id="dropdown-basic" + > + Add Filter - - setComponents([...components, - - - - ])}>Chart - - setComponents([...components, - - - - ])}>Gallery - - setComponents([...components, - - - - ])}>Directory - - setComponents([...components, - - - - ])}>Embed - - setComponents([...components, - - - - ])}>Text + { + // console.log("") + addComponent("Chart"); + }} + > + Chart + + addComponent("Directory")} + > + Directory + + addComponent("Embed")}> + Embed + + addComponent("Gallery")}> + Gallery + + addComponent("Text")}> + Text + @@ -322,6 +440,7 @@ const ContentForm = ({ content, onChange }) => { const updateSections = (newSections) => { setSections(newSections); + console.log("Sections:", newSections); onChange(newSections); }; @@ -385,7 +504,7 @@ const ContentForm = ({ content, onChange }) => { style={{ backgroundColor: "#E3E9F5", padding: "16px 16px 28px 16px", - width: "calc(100% - 264px)" + width: "calc(100% - 264px)", }} > {selectedSection === null ? null : ( diff --git a/src/components/dashboard/DirectoryForm.module.css b/src/components/dashboard/DirectoryForm.module.css index e7b60e5..c28e03b 100644 --- a/src/components/dashboard/DirectoryForm.module.css +++ b/src/components/dashboard/DirectoryForm.module.css @@ -1,12 +1,10 @@ .directory::-webkit-scrollbar { width: 5px; } - .directory::-webkit-scrollbar-track { background-color: transparent; } .directory::-webkit-scrollbar-thumb { - /* border: 15px solid transparent; */ border-radius: 4px; background-color: #a9a9a9; } @@ -16,10 +14,9 @@ .addButton { border: 1px solid #226dff; - background: var(--drop-down-fill, #1346aa0f); + background: transparent; color: #226dff; font-size: 16px; - margin-top: 16px; width: 100px; height: 40px; font-weight: 600; diff --git a/src/components/dashboard/DirectoryForm.tsx b/src/components/dashboard/DirectoryForm.tsx index 1b420aa..12ce89e 100644 --- a/src/components/dashboard/DirectoryForm.tsx +++ b/src/components/dashboard/DirectoryForm.tsx @@ -48,6 +48,7 @@ const DirectoryFormItem = ({ .child(filename) .getDownloadURL() .then((url) => { + console.log(url); newItem = { ...newItem, image: url }; updateItem(newItem); }); @@ -56,7 +57,7 @@ const DirectoryFormItem = ({ return (
@@ -121,9 +122,11 @@ const DirectoryFormItem = ({ fontWeight: "500", }} onClick={() => { - setDirectoryItems((directoryItems) => - directoryItems.filter((_, i) => i !== index) + const filterItems = directoryItems.filter( + (_, i) => i !== index ); + // console.log(filterItems); + setDirectoryItems(filterItems); }} > Delete @@ -132,8 +135,19 @@ const DirectoryFormItem = ({ ); }; -const DirectoryForm = ({ items }) => { - const [isOpen, setIsOpen] = useState(false); +interface DirectoryState { + items: DirectoryItem[]; +} + +const DirectoryForm = ({ + directoryState, + setDirectoryState, + deleteComponent, +}: { + directoryState: DirectoryState; + setDirectoryState: (newState: DirectoryState) => void; + deleteComponent: () => void; +}) => { const defaultDirectoryItem: DirectoryItem = { name: "", description: "", @@ -141,7 +155,16 @@ const DirectoryForm = ({ items }) => { image: "", }; //might have to lift this state later to avoid one shared state - const [directoryItems, setDirectoryItems] = useState(items); + // const [directoryItems, setDirectoryItems] = useState( + // data.items + // ); + const { items: directoryItems } = directoryState; + + const setDirectoryItems = (newItems) => { + // console.log(newItems); + setDirectoryState({ ...directoryState, items: newItems }); + }; + /* directoryItem { @@ -156,7 +179,6 @@ const DirectoryForm = ({ items }) => { style={{ width: "100%", height: "100%", - padding: "16px", display: "flex", flexDirection: "column", }} @@ -164,34 +186,54 @@ const DirectoryForm = ({ items }) => {
{/* {directoryItems.length} */} - {directoryItems.map((directoryItem, index) => ( - // console.log() - - ))} - + + +
); diff --git a/src/components/dashboard/EventInfoComponent.css b/src/components/dashboard/EventInfoComponent.css index f0adb71..7a3c319 100644 --- a/src/components/dashboard/EventInfoComponent.css +++ b/src/components/dashboard/EventInfoComponent.css @@ -10,7 +10,6 @@ .event-description { font-family: Arial, sans-serif; font-size: 16px; - color: #7f8c8d; line-height: 1.6; margin-bottom: 12px; } diff --git a/src/components/dashboard/EventInfoComponent.tsx b/src/components/dashboard/EventInfoComponent.tsx index 682db54..a0d4744 100644 --- a/src/components/dashboard/EventInfoComponent.tsx +++ b/src/components/dashboard/EventInfoComponent.tsx @@ -1,6 +1,5 @@ import React from "react"; import './EventInfoComponent.css'; -import Collapsible from 'components/collapsible'; interface EventInfoComponentProps { description: string; @@ -8,7 +7,7 @@ interface EventInfoComponentProps { const EventInfoComponent: React.FC = ({ description }) => { return ( -

{description}

+

); }; diff --git a/src/components/dashboard/ProviderGallery.tsx b/src/components/dashboard/ProviderGallery.tsx index a444f20..af661fe 100644 --- a/src/components/dashboard/ProviderGallery.tsx +++ b/src/components/dashboard/ProviderGallery.tsx @@ -1,6 +1,7 @@ -import React, { useState, useEffect } from "react"; +import React, { useState, useEffect, Provider } from "react"; import ProviderGallerySlide from "./ProviderGallerySlide"; import { storage } from "../../store"; +import { Button } from "react-bootstrap"; interface GallerySlide { title: string; @@ -8,12 +9,24 @@ interface GallerySlide { imgLink: string; } +interface GalleryState { + slidesArray: GallerySlide[]; +} + export default function ProviderGallery({ - slidesArray = [], + galleryState, + setGalleryState, + deleteComponent, }: { - slidesArray?: GallerySlide[]; + galleryState: GalleryState; + setGalleryState: (newState: GalleryState) => void; + deleteComponent: () => void; }) { - const [slides, setSlides] = useState(slidesArray); + const { slidesArray: slides } = galleryState; + + const setSlides = (newSlides) => { + setGalleryState({ ...galleryState, slidesArray: newSlides }); + }; const defaultSlide: GallerySlide = { title: "", @@ -21,12 +34,6 @@ export default function ProviderGallery({ imgLink: "", }; - useEffect(() => { - if (!slides || slides.length === 0) { - setSlides([{ ...defaultSlide }]); - } - }, [slides]); - const handleSlideDataChange = ( index: number, field: keyof GallerySlide, @@ -39,10 +46,8 @@ export default function ProviderGallery({ }; const handleDelete = (index: number) => { - if (slides.length > 1) { - const newSlides = slides.filter((_, i) => i !== index); - setSlides(newSlides); - } + const newSlides = slides.filter((_, i) => i !== index); + setSlides(newSlides); }; const handleAdd = (index: number) => { @@ -85,12 +90,46 @@ export default function ProviderGallery({ }; return ( -

+
{renderSlides()} - {/*TO BE DELETED */} -
-

Current Data:

-
{JSON.stringify(slides, null, 2)}
+
+ +
); diff --git a/src/components/dashboard/ProviderGallerySlide.tsx b/src/components/dashboard/ProviderGallerySlide.tsx index a79440a..2f77985 100644 --- a/src/components/dashboard/ProviderGallerySlide.tsx +++ b/src/components/dashboard/ProviderGallerySlide.tsx @@ -64,13 +64,18 @@ export default function ProviderGallerySlide({
-
+
-
); diff --git a/src/components/dashboard/RowForm.tsx b/src/components/dashboard/RowForm.tsx index d563522..b2643fb 100644 --- a/src/components/dashboard/RowForm.tsx +++ b/src/components/dashboard/RowForm.tsx @@ -64,7 +64,7 @@ const RowForm = (props) => { address: [], description: "", buildingNum: [], - stationNum: [], + stationNum: "", childcare: [false], epic: [false], hours: {}, @@ -386,7 +386,7 @@ const RowForm = (props) => { void; + deleteComponent: () => void; + }) { const CustomImage = Image.extend({ addAttributes() { return { @@ -60,7 +70,13 @@ export function SimpleEditor() { CustomImage, Blockquote ], - content: '

ex. "Changing lives one bit at a time..."

', + content: editorState.description, + onUpdate: ({ editor }) => { + setEditorState({ + ...editorState, + description: editor.getHTML() + }); + } }) as Editor; const [modalIsOpen, setIsOpen] = useState(false); @@ -129,7 +145,7 @@ export function SimpleEditor() { const addImage = useCallback(() => { const imageUrl: string | null = prompt("Enter the image URL"); if (imageUrl) { - editor.chain().focus().setImage({ src: imageUrl }).run(); + editor.chain().focus().setImage({ src: imageUrl }).run(); } }, [editor]); @@ -169,7 +185,7 @@ export function SimpleEditor() {
- +
- + @@ -341,8 +357,8 @@ export function SimpleEditor() { }} > Blockquote - - + +
@@ -357,6 +373,24 @@ export function SimpleEditor() { onSaveLink={saveLink} onRemoveLink={removeLink} /> + +
+ +
); } diff --git a/src/components/dashboard/embed-component/EmbedComponent.tsx b/src/components/dashboard/embed-component/EmbedComponent.tsx index 7221680..5a02709 100644 --- a/src/components/dashboard/embed-component/EmbedComponent.tsx +++ b/src/components/dashboard/embed-component/EmbedComponent.tsx @@ -4,7 +4,7 @@ import ReactPlayer from 'react-player'; interface EventInfo { title: string, videoUrl: string; - thumbnail: string; + // thumbnail: string; } interface EmbedComponentProps { @@ -13,6 +13,7 @@ interface EmbedComponentProps { const EmbedComponent: React.FC = ({ eventInfo }) => { const [isPlaying, setIsPlaying] = useState(false); + const DEFAULT_THUMBNAIL = "https://joeferry.com/wp-content/plugins/video-thumbnails/default.jpg"; const handlePlayVideo = () => { setIsPlaying(true); @@ -22,7 +23,7 @@ const EmbedComponent: React.FC = ({ eventInfo }) => {
{!isPlaying ? (
- Video thumbnail + Video thumbnail
diff --git a/src/components/dashboard/embed-component/EmbedForm.tsx b/src/components/dashboard/embed-component/EmbedForm.tsx index f2b4acb..b5d5ed1 100644 --- a/src/components/dashboard/embed-component/EmbedForm.tsx +++ b/src/components/dashboard/embed-component/EmbedForm.tsx @@ -1,98 +1,123 @@ -import React, { useState } from 'react'; +import React from "react"; +interface EmbedState { + embedLink: string; + title: string; +} -const EmbedForm: React.FC = () => { - const [embedLink, setEmbedLink] = useState(''); - const [title, setTitle] = useState(''); +const EmbedForm = ({ + embedState, + setEmbedState, + deleteComponent, +}: { + embedState: EmbedState; + setEmbedState: (newState: EmbedState) => void; + deleteComponent: () => void; +}) => { + const { embedLink, title } = embedState; - return ( -
-
- - setTitle(e.target.value)} - style={styles.input} - /> -
+ const setEmbedLink = (newEmbedLink) => { + setEmbedState({ ...embedState, embedLink: newEmbedLink }); + }; + const setTitle = (newTitle) => { + setEmbedState({ ...embedState, title: newTitle }); + }; -
- -