custom popups are basicly working 🍄

This commit is contained in:
Anton 2023-08-22 14:54:57 +02:00
parent d6e780436f
commit 6bd062c1b3
15 changed files with 157 additions and 113 deletions

View File

@ -1,7 +1,7 @@
import {useState, useRef} from 'react' import {useState, useRef} from 'react'
import {Link} from 'react-router-dom' import {Link} from 'react-router-dom'
import ErrorText from '../Typography/ErrorText' import ErrorText from '../Typography/ErrorText'
import InputText from '../Input/InputText' import {TextInput} from '../Input/TextInput'
import * as React from 'react' import * as React from 'react'
export function LoginPage(){ export function LoginPage(){
@ -44,9 +44,9 @@ export function LoginPage(){
<div className="tw-mb-4"> <div className="tw-mb-4">
<InputText type="email" defaultValue={loginObj.emailId} containerStyle="tw-mt-4" labelTitle="E-Mail" updateFormValue={(v) => updateFormValue(v)}/> <TextInput type="email" defaultValue={loginObj.emailId} containerStyle="tw-mt-4" labelTitle="E-Mail" updateFormValue={(v) => updateFormValue(v)}/>
<InputText defaultValue={loginObj.password} type="password" containerStyle="tw-mt-4" labelTitle="Password" updateFormValue={(v) => updateFormValue(v)}/> <TextInput defaultValue={loginObj.password} type="password" containerStyle="tw-mt-4" labelTitle="Password" updateFormValue={(v) => updateFormValue(v)}/>
</div> </div>

View File

@ -1,7 +1,7 @@
import { useState, useRef } from 'react' import { useState, useRef } from 'react'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import ErrorText from '../Typography/ErrorText' import ErrorText from '../Typography/ErrorText'
import InputText from '../Input/InputText' import {TextInput} from '../Input/TextInput'
import * as React from 'react' import * as React from 'react'
export function SignupPage() { export function SignupPage() {
@ -45,13 +45,9 @@ export function SignupPage() {
<form onSubmit={(e) => submitForm(e)}> <form onSubmit={(e) => submitForm(e)}>
<div className="mb-4"> <div className="mb-4">
<TextInput defaultValue={registerObj.name} containerStyle="tw-mt-4" labelTitle="Name" updateFormValue={updateFormValue} />
<InputText defaultValue={registerObj.name} containerStyle="tw-mt-4" labelTitle="Name" updateFormValue={updateFormValue} /> <TextInput defaultValue={registerObj.emailId} containerStyle="tw-mt-4" labelTitle="E-Mail" updateFormValue={updateFormValue} />
<TextInput defaultValue={registerObj.password} type="password" containerStyle="tw-mt-4" labelTitle="Password" updateFormValue={updateFormValue} />
<InputText defaultValue={registerObj.emailId} containerStyle="tw-mt-4" labelTitle="E-Mail" updateFormValue={updateFormValue} />
<InputText defaultValue={registerObj.password} type="password" containerStyle="tw-mt-4" labelTitle="Password" updateFormValue={updateFormValue} />
</div> </div>
<ErrorText styleClass="tw-mt-8">{errorMessage}</ErrorText> <ErrorText styleClass="tw-mt-8">{errorMessage}</ErrorText>

View File

@ -1,44 +0,0 @@
import { useEffect, useState } from "react"
import * as React from "react"
type InputTextProps = {
labelTitle?: string;
labelStyle?: string;
type?: string;
dataField?: string;
containerStyle?: string;
defaultValue: string;
placeholder?: string;
updateFormValue?: (value: string ) => void;
}
function InputText({labelTitle, labelStyle, type, dataField, containerStyle, defaultValue, placeholder, updateFormValue} : InputTextProps){
const [value, setValue] = useState<string>(defaultValue)
useEffect(() => {
setValue(defaultValue)
}, [defaultValue])
const updateInputValue = (val : string) => {
setValue(val)
if(updateFormValue)
updateFormValue(val)
}
return(
<div className={`tw-form-control tw-w-full ${containerStyle}`}>
{labelTitle ? <label className="tw-label">
<span className={"tw-label-text tw-text-base-content " + labelStyle}>{labelTitle}</span>
</label>
: " "}
<input type={type || "text"} name={dataField} value={value} placeholder={placeholder || ""} onChange={(e) => updateInputValue(e.target.value)}className="tw-input tw-input-bordered tw-w-full " />
</div>
)
}
export default InputText

View File

@ -15,30 +15,20 @@ type TextAreaProps = {
function TextAreaInput({ labelTitle, dataField, labelStyle, containerStyle, inputStyle, defaultValue, placeholder, updateFormValue }: TextAreaProps) { export function TextAreaInput({ labelTitle, dataField, labelStyle, containerStyle, inputStyle, defaultValue, placeholder, updateFormValue }: TextAreaProps) {
const [value, setValue] = useState<string>(defaultValue)
useEffect(() => {
setValue(defaultValue)
}, [defaultValue])
const updateInputValue = (val: string) => {
setValue(val)
if (updateFormValue)
updateFormValue(val)
}
return ( return (
<div className={`tw-form-control tw-w-full ${containerStyle ? containerStyle : ""}`}> <div className={`tw-form-control tw-w-full ${containerStyle ? containerStyle : ""}`}>
{labelTitle ? <label className="tw-label"> {labelTitle ? <label className="tw-label">
<span className={"tw-label-text tw-text-base-content " + labelStyle}>{labelTitle}</span> <span className={"tw-label-text tw-text-base-content " + labelStyle}>{labelTitle}</span>
</label> : ""} </label> : ""}
<textarea value={value} name={dataField} className={`tw-textarea tw-textarea-bordered tw-w-full tw-leading-5 ${inputStyle ? inputStyle : ""}`} placeholder={placeholder || ""} onChange={(e) => updateInputValue(e.target.value)}></textarea> <textarea defaultValue={defaultValue} name={dataField} className={`tw-textarea tw-textarea-bordered tw-w-full tw-leading-5 ${inputStyle ? inputStyle : ""}`} placeholder={placeholder || ""} onChange={(e) => updateFormValue&& updateFormValue(e.target.value)}></textarea>
</div> </div>
) )
} }
export default TextAreaInput

View File

@ -0,0 +1,29 @@
import { useEffect, useState } from "react"
import * as React from "react"
type InputTextProps = {
labelTitle?: string;
labelStyle?: string;
type?: string;
dataField?: string;
containerStyle?: string;
defaultValue?: string;
placeholder?: string;
updateFormValue?: (value: string ) => void;
}
export function TextInput({labelTitle, labelStyle, type, dataField, containerStyle, defaultValue, placeholder, updateFormValue} : InputTextProps){
return(
<div className={`tw-form-control tw-w-full ${containerStyle}`}>
{labelTitle ? <label className="tw-label">
<span className={"tw-label-text tw-text-base-content " + labelStyle}>{labelTitle}</span>
</label>
: " "}
<input type={type || "text"} name={dataField} defaultValue={defaultValue} placeholder={placeholder || ""} onChange={(e) => updateFormValue&& updateFormValue(e.target.value)}className="tw-input tw-input-bordered tw-w-full " />
</div>
)
}

View File

@ -0,0 +1,2 @@
export {TextAreaInput} from "./TextAreaInput"
export {TextInput} from "./TextInput"

View File

@ -0,0 +1,7 @@
import * as React from 'react'
export const ItemForm = ({ children }:{children?: React.ReactNode}) => {
return (
<div>{children}</div>
)
}

View File

@ -0,0 +1,7 @@
import * as React from 'react'
export const ItemView = ({ children }:{children?: React.ReactNode}) => {
return (
<div>{children}</div>
)
}

View File

@ -7,7 +7,7 @@ import { useTags } from './hooks/useTags'
import { useAddItem, useItems, useResetItems } from './hooks/useItems' import { useAddItem, useItems, useResetItems } from './hooks/useItems'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { useAddLayer } from './hooks/useLayers' import { useAddLayer } from './hooks/useLayers'
import ItemFormPopup, { ItemFormPopupProps } from './Subcomponents/ItemFormPopup' import { ItemFormPopupProps, ItemFormPopup } from './Subcomponents/ItemFormPopup'
export const Layer = (props: LayerProps) => { export const Layer = (props: LayerProps) => {
@ -86,14 +86,38 @@ export const Layer = (props: LayerProps) => {
} }
return ( return (
<Marker icon={MarkerIconFactory(props.markerShape, color1, color2, props.markerIcon)} key={place.id} position={[place.position.coordinates[1], place.position.coordinates[0]]}> <Marker icon={MarkerIconFactory(props.markerShape, color1, color2, props.markerIcon)} key={place.id} position={[place.position.coordinates[1], place.position.coordinates[0]]}>
<ItemViewPopup item={place} setItemFormPopup={props.setItemFormPopup} />
{
(props.children && React.Children.toArray(props.children).some(e => React.isValidElement(e) && typeof e.type !== "string" && e.type.name === "ItemForm") ?
React.Children.toArray(props.children).map((child) =>
React.isValidElement(child) && typeof child.type !== "string" && child.type.name === "ItemView" ?
<ItemViewPopup key={place.id} item={place} setItemFormPopup={props.setItemFormPopup} >{child}</ItemViewPopup>
: ""
)
:
<>
<ItemViewPopup item={place} setItemFormPopup={props.setItemFormPopup} />
</>)
}
</Marker> </Marker>
); );
}) })
} }
{props.children} {props.children}
{props.itemFormPopup && props.itemFormPopup.layer.name == props.name && {props.itemFormPopup && props.itemFormPopup.layer!.name == props.name &&
<ItemFormPopup position={props.itemFormPopup.position} layer={props.itemFormPopup.layer} setItemFormPopup={setItemFormPopup} item={props.itemFormPopup.item} api={props.api} /> (props.children && React.Children.toArray(props.children).some(e => React.isValidElement(e) && typeof e.type !== "string" && e.type.name === "ItemForm") ?
React.Children.toArray(props.children).map((child) =>
React.isValidElement(child) && typeof child.type !== "string" && child.type.name === "ItemForm" ?
<ItemFormPopup key={props.setItemFormPopup?.name} position={props.itemFormPopup!.position} layer={props.itemFormPopup!.layer} setItemFormPopup={setItemFormPopup} item={props.itemFormPopup!.item} api={props.api} >{child}</ItemFormPopup>
: ""
)
:
<>
<ItemFormPopup position={props.itemFormPopup!.position} layer={props.itemFormPopup!.layer} setItemFormPopup={setItemFormPopup} item={props.itemFormPopup!.item} api={props.api} />
</>)
} }
</> </>
) )

View File

@ -1,21 +1,25 @@
import * as React from 'react' import * as React from 'react'
import { LatLng } from 'leaflet' import { LatLng } from 'leaflet'
import { Popup as LeafletPopup, useMap } from 'react-leaflet' import { Popup as LeafletPopup, useMap } from 'react-leaflet'
import { useEffect, useState } from 'react' import { useEffect, useRef, useState } from 'react'
import { useAddItem, useUpdateItem } from '../hooks/useItems' import { useAddItem, useUpdateItem } from '../hooks/useItems'
import { Geometry, LayerProps, Item, ItemsApi } from '../../../types' import { Geometry, LayerProps, Item, ItemsApi } from '../../../types'
import TextAreaInput from '../../Input/TextAreaInput' import {TextAreaInput} from '../../Input/TextAreaInput'
import InputText from '../../Input/InputText' import {TextInput} from '../../Input/TextInput'
export interface ItemFormPopupProps { export interface ItemFormPopupProps {
position: LatLng, position: LatLng,
layer: LayerProps, layer: LayerProps,
item?: Item, item?: Item,
api?: ItemsApi<any>, api?: ItemsApi<any>,
children?: React.ReactNode,
setItemFormPopup: React.Dispatch<React.SetStateAction<any>> setItemFormPopup: React.Dispatch<React.SetStateAction<any>>
} }
export default function ItemFormPopup(props: ItemFormPopupProps) { export function ItemFormPopup(props: ItemFormPopupProps) {
const formRef = useRef<HTMLFormElement>(null);
const [spinner, setSpinner] = useState(false); const [spinner, setSpinner] = useState(false);
@ -25,30 +29,29 @@ export default function ItemFormPopup(props: ItemFormPopupProps) {
const handleSubmit = async (evt: any) => { const handleSubmit = async (evt: any) => {
const formItem: Item = {} as Item; const formItem: Item = {} as Item;
Array.from(evt.target).forEach((input: HTMLFormElement) => { Array.from(evt.target).forEach((input: HTMLInputElement) => {
if (input.name) { if (input.name) {
console.log(input.name + ": " + input.value);
formItem[input.name] = input.value; formItem[input.name] = input.value;
} }
}); });
formItem['position']=new Geometry(props.position.lng, props.position.lat); formItem['position'] = new Geometry(props.position.lng, props.position.lat);
evt.preventDefault(); evt.preventDefault();
setSpinner(true); setSpinner(true);
if (props.item) { if (props.item) {
formItem['id']=props.item.id; formItem['id'] = props.item.id;
await props.api?.updateItem!(formItem); await props.api?.updateItem!(formItem);
formItem['api']=props.api; formItem['api'] = props.api;
formItem['layer']=props.layer; formItem['layer'] = props.layer;
await updateItem(formItem); await updateItem(formItem);
setSpinner(false); setSpinner(false);
map.closePopup(); map.closePopup();
} }
else { else {
formItem['id']=crypto.randomUUID(); formItem['id'] = crypto.randomUUID();
await props.api?.createItem!(formItem); await props.api?.createItem!(formItem);
formItem['api']=props.api; formItem['api'] = props.api;
formItem['layer']=props.layer; formItem['layer'] = props.layer;
await addItem(formItem); await addItem(formItem);
setSpinner(false); setSpinner(false);
map.closePopup(); map.closePopup();
@ -57,17 +60,41 @@ export default function ItemFormPopup(props: ItemFormPopupProps) {
} }
const resetPopup = () => {
if (formRef.current) {
formRef.current.reset();
}
}
useEffect(() => {
resetPopup();
}, [props.position])
return ( return (
<LeafletPopup minWidth={275} maxWidth={275} autoPanPadding={[20, 5]} <LeafletPopup minWidth={275} maxWidth={275} autoPanPadding={[20, 5]}
eventHandlers={{ eventHandlers={{
// remove: resetPopup remove: () => {
setTimeout(function() {
resetPopup()
}, 100);
}
}} }}
position={props.position}> position={props.position}>
<form onSubmit={e => handleSubmit(e)}> <form ref={formRef} onReset={resetPopup} onSubmit={e => handleSubmit(e)}>
<div className='tw-flex tw-justify-center'><b className="tw-text-xl tw-font-bold">New {props.layer.name}</b></div> <div className='tw-flex tw-justify-center'><b className="tw-text-xl tw-font-bold">New {props.layer.name}</b></div>
<InputText type="text" placeholder="Name" dataField="name" defaultValue={props.item? props.item.name : ""} /> {props.children ? props.children :
<TextAreaInput placeholder="Text" dataField="text" defaultValue={props.item ? props.item.text : ""} inputStyle='tw-h-40 tw-mt-5' /> <>
<div className='tw-flex tw-justify-center'><button className={spinner ? 'tw-btn tw-loading tw-mt-5 tw-place-self-center' : 'tw-btn tw-mt-5 tw-place-self-center'}>Save</button></div> <TextInput type="text" placeholder="Name" dataField="name" defaultValue={props.item ? props.item.name : ""} />
<TextAreaInput placeholder="Text" dataField="text" defaultValue={props.item ? props.item.text : ""} inputStyle='tw-h-40 tw-mt-5' />
</>
}
<div className='tw-flex tw-justify-center'>
<button className={spinner ? 'tw-btn tw-btn-disabled tw-mt-5 tw-place-self-center' : 'tw-btn tw-mt-5 tw-place-self-center'} type='submit'>{spinner ? <span className="tw-loading tw-loading-spinner"></span> : 'Save'}</button>
</div>
</form> </form>
</LeafletPopup> </LeafletPopup>
) )

View File

@ -1,13 +1,14 @@
import * as React from 'react' import * as React from 'react'
import { Popup as LeafletPopup, useMap } from 'react-leaflet' import { Popup as LeafletPopup, useMap } from 'react-leaflet'
import { Item} from '../../../types' import { Item } from '../../../types'
import { ItemFormPopupProps } from './ItemFormPopup' import { ItemFormPopupProps } from './ItemFormPopup'
import {HeaderView} from './HeaderView' import { HeaderView } from './HeaderView'
import StartEndView from './StartEndView' import StartEndView from './StartEndView'
import { TextView } from './TextView' import { TextView } from './TextView'
export interface ItemViewPopupProps { export interface ItemViewPopupProps {
item: Item, item: Item,
children?: React.ReactNode;
setItemFormPopup?: React.Dispatch<React.SetStateAction<ItemFormPopupProps | null>> setItemFormPopup?: React.Dispatch<React.SetStateAction<ItemFormPopupProps | null>>
} }
@ -19,13 +20,14 @@ export const ItemViewPopup = (props: ItemViewPopupProps) => {
return ( return (
<LeafletPopup maxHeight={377} minWidth={275} maxWidth={275} autoPanPadding={[20, 5]}> <LeafletPopup maxHeight={377} minWidth={275} maxWidth={275} autoPanPadding={[20, 5]}>
<div> <div>
<HeaderView item={props.item} setItemFormPopup={props.setItemFormPopup}/> <HeaderView item={props.item} setItemFormPopup={props.setItemFormPopup} />
<div className='tw-overflow-y-auto tw-max-h-72'> {props.children ? props.children :
{item.start && item.end && <div className='tw-overflow-y-auto tw-max-h-72'>
<StartEndView item={props.item} /> {item.start && item.end &&
<StartEndView item={props.item} />}
<TextView item={props.item} />
</div>
} }
<TextView item={props.item}/>
</div>
</div> </div>
</LeafletPopup> </LeafletPopup>
) )

View File

@ -1,3 +1,6 @@
export { UtopiaMap } from './UtopiaMap' export { UtopiaMap } from './UtopiaMap';
export { Layer } from './Layer'; export { Layer } from './Layer';
export { Tags } from "./Tags"; export { Tags } from "./Tags";
export {ItemViewPopup} from './Subcomponents/ItemViewPopup';
export {ItemForm} from './ItemForm';
export {ItemView} from './ItemView';

View File

@ -1,7 +1,7 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import {TitleCard} from '../Templates/TitleCard' import {TitleCard} from '../Templates/TitleCard'
import InputText from '../Input/InputText' import {TextInput} from '../Input/TextInput'
import TextAreaInput from '../Input/TextAreaInput' import {TextAreaInput} from '../Input/TextAreaInput'
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import {useNavigate} from 'react-router-dom' import {useNavigate} from 'react-router-dom'
import * as React from 'react' import * as React from 'react'
@ -62,7 +62,7 @@ export function Settings({useAuth}) {
<div className="tw-grid tw-grid-cols-1 tw-md:grid-cols-2 tw-gap-6"> <div className="tw-grid tw-grid-cols-1 tw-md:grid-cols-2 tw-gap-6">
<InputText placeholder="Name" defaultValue={user?.first_name ? user.first_name : ""} updateFormValue={(v) => setName(v)} /> <TextInput placeholder="Name" defaultValue={user?.first_name ? user.first_name : ""} updateFormValue={(v) => setName(v)} />
</div> </div>
<div className="tw-grid tw-grid-cols-1 tw-md:grid-cols-1 tw-gap-6 tw-pt-6 tw-pb-6"> <div className="tw-grid tw-grid-cols-1 tw-md:grid-cols-1 tw-gap-6 tw-pt-6 tw-pb-6">
<TextAreaInput placeholder="About me, Contact, #Tags, ..." defaultValue={user?.description ? user.description : ""} updateFormValue={(v) => setText(v)} inputStyle='tw-h-64'/> <TextAreaInput placeholder="About me, Contact, #Tags, ..." defaultValue={user?.description ? user.description : ""} updateFormValue={(v) => setText(v)} inputStyle='tw-h-64'/>
@ -71,8 +71,8 @@ export function Settings({useAuth}) {
<div className="tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6"> <div className="tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6">
<InputText type='email' placeholder="E-Mail" defaultValue={user?.email ? user.email : ""} updateFormValue={(v) => setEmail(v)} /> <TextInput type='email' placeholder="E-Mail" defaultValue={user?.email ? user.email : ""} updateFormValue={(v) => setEmail(v)} />
<InputText type='password' placeholder="new Password" defaultValue={user?.password ? user.password : ""} updateFormValue={(v) => { <TextInput type='password' placeholder="new Password" defaultValue={user?.password ? user.password : ""} updateFormValue={(v) => {
setPassword(v); setPassword(v);
setPasswordChanged(true); setPasswordChanged(true);
}} /> }} />

View File

@ -1,9 +1,10 @@
export { UtopiaMap, Layer, Tags } from './Components/Map/index'; export { UtopiaMap, Layer, Tags, ItemViewPopup, ItemForm, ItemView } from './Components/Map/index';
export {AppShell, Content, SideBar} from "./Components/AppShell" export {AppShell, Content, SideBar} from "./Components/AppShell"
export {AuthProvider, useAuth, LoginPage, SignupPage} from "./Components/Auth" export {AuthProvider, useAuth, LoginPage, SignupPage} from "./Components/Auth"
export {Settings} from './Components/Profile' export {Settings} from './Components/Profile'
export {Quests, Modal} from './Components/Gaming' export {Quests, Modal} from './Components/Gaming'
export {TitleCard, CardPage} from './Components/Templates' export {TitleCard, CardPage} from './Components/Templates'
export {TextInput, TextAreaInput} from './Components/Input'
import "./index.css" import "./index.css"

View File

@ -12,7 +12,7 @@ export interface UtopiaMapProps {
export interface LayerProps { export interface LayerProps {
data?: Item[], data?: Item[],
children?: React.ReactNode children?: React.ReactNode,
name: string, name: string,
menuIcon: string, menuIcon: string,
menuColor: string, menuColor: string,
@ -28,16 +28,16 @@ export interface LayerProps {
export class Item { export class Item {
id: string | number; id: string | number;
date_created?: string;
date_updated?: string | null;
name: string; name: string;
text: string; text: string;
position: Geometry; position: Geometry;
[key: string]: any; date_created?: string;
date_updated?: string | null;
start?: string; start?: string;
end?: string; end?: string;
tags?: number[]; tags?: number[];
api?: ItemsApi<any> api?: ItemsApi<any>;
[key: string]: any;
constructor(id:string|number,name:string,text:string,position:Geometry, layer?: LayerProps, api?: ItemsApi<any>){ constructor(id:string|number,name:string,text:string,position:Geometry, layer?: LayerProps, api?: ItemsApi<any>){
this.id = id; this.id = id;
this.name = name; this.name = name;