adjust invitepage

This commit is contained in:
Anton Tranelis 2025-12-16 10:40:24 +01:00
parent c1da299732
commit eeb55832e1
5 changed files with 76 additions and 46 deletions

View File

@ -28,6 +28,7 @@ export function AppShell({
<ContextWrapper>
<div className='tw:flex tw:flex-col tw:h-full'>
<SetAppState
appName={appName}
assetsApi={assetsApi}
embedded={embedded}
openCollectiveApiKey={openCollectiveApiKey}

View File

@ -5,11 +5,13 @@ import { useSetAppState } from './hooks/useAppState'
import type { AssetsApi } from '#types/AssetsApi'
export const SetAppState = ({
appName,
assetsApi,
embedded,
openCollectiveApiKey,
hideSignup,
}: {
appName: string
assetsApi: AssetsApi
embedded?: boolean
openCollectiveApiKey?: string
@ -17,6 +19,10 @@ export const SetAppState = ({
}) => {
const setAppState = useSetAppState()
useEffect(() => {
setAppState({ appName })
}, [appName, setAppState])
useEffect(() => {
setAppState({ assetsApi })
}, [assetsApi, setAppState])

View File

@ -4,6 +4,7 @@ import { useCallback, useState, createContext, useContext } from 'react'
import type { AssetsApi } from '#types/AssetsApi'
interface AppState {
appName: string
assetsApi: AssetsApi
sideBarOpen: boolean
sideBarSlim: boolean
@ -16,6 +17,7 @@ interface AppState {
type UseAppManagerResult = ReturnType<typeof useAppManager>
const initialAppState: AppState = {
appName: '',
assetsApi: {} as AssetsApi,
sideBarOpen: false,
sideBarSlim: false,

View File

@ -2,6 +2,7 @@ import { useEffect, useState } from 'react'
import { useNavigate, useParams } from 'react-router-dom'
import { toast } from 'react-toastify'
import { useAppState } from '#components/AppShell/hooks/useAppState'
import { useAuth } from '#components/Auth/useAuth'
import { useUpdateItem } from '#components/Map/hooks/useItems'
import { useMyProfile } from '#components/Map/hooks/useMyProfile'
@ -24,6 +25,7 @@ export function InvitePage({ inviteApi, itemsApi }: Props) {
const { id } = useParams<{ id: string }>()
const navigate = useNavigate()
const updateItem = useUpdateItem()
const { appName } = useAppState()
const { myProfile, isUserProfileLayerLoaded, createEmptyProfile } = useMyProfile()
@ -172,23 +174,25 @@ export function InvitePage({ inviteApi, itemsApi }: Props) {
if (isAuthenticated) {
return (
<MapOverlayPage backdrop className='tw:max-w-xs tw:h-fit'>
<h2 className='tw-text-2xl tw-font-semibold tw-mb-2 tw-text-center'>Confirmation</h2>
<h2 className='tw:text-2xl tw:font-semibold tw:mb-2 tw:text-center'>Confirmation</h2>
{invitingProfile ? (
<div className='tw-text-center tw-mb-4'>
<p className='tw-text-sm tw-text-gray-600'>
<>
<p className='tw:text-sm tw:text-base-content/70 tw:text-center'>
Do you want to follow <strong>{invitingProfile.name}</strong>?
</p>
<div className='tw-flex tw:justify-center tw:mt-4'>
<button className='tw-btn tw-btn-primary' onClick={confirmFollow}>
Yes
</button>
<button className='tw-btn tw-btn-secondary' onClick={goToStart}>
<div className='tw:card-actions tw:justify-between'>
<button className='tw:btn tw:btn-ghost' onClick={goToStart}>
No
</button>
<button className='tw:btn tw:btn-primary' onClick={confirmFollow}>
Yes
</button>
</div>
</div>
</>
) : (
<p className='tw-text-center'>Validating invite...</p>
<div className='tw:flex tw:justify-center'>
<span className='tw:loading tw:loading-spinner tw:loading-md'></span>
</div>
)}
</MapOverlayPage>
)
@ -196,25 +200,28 @@ export function InvitePage({ inviteApi, itemsApi }: Props) {
return (
<MapOverlayPage backdrop className='tw:max-w-xs tw:h-fit'>
<h2 className='tw:text-2xl tw:font-semibold tw:mb-2 tw:text-center'>Invitation</h2>
{invitingProfile ? (
<div className='tw-text-center tw-mb-4'>
<p className='tw-text-lg tw-font-semibold'>Welcome to Utopia!</p>
<p className='tw-text-sm tw-text-gray-600'>
You have been invited by: <strong>{invitingProfile.name}</strong> to join the Utopia
community.
<>
<h2 className='tw:text-2xl tw:font-semibold tw:mb-2 tw:text-center'>
Welcome{appName && <> to {appName}</>}!
</h2>
<p className='tw:text-sm tw:text-base-content/70 tw:text-center'>
You have been invited by <strong>{invitingProfile.name}</strong> to join{' '}
{appName || 'the community'}.
</p>
<div className='tw-flex tw:justify-center tw:mt-4'>
<button className='tw-btn tw-btn-primary' onClick={goToSignup}>
{'Sign Up'}
</button>
<button className='tw-btn tw-btn-secondary' onClick={goToLogin}>
<div className='tw:card-actions tw:justify-between'>
<button className='tw:btn tw:btn-ghost' onClick={goToLogin}>
Login
</button>
<button className='tw:btn tw:btn-primary' onClick={goToSignup}>
Sign Up
</button>
</div>
</div>
</>
) : (
<p className='tw-text-center'>Validating invite...</p>
<div className='tw:flex tw:justify-center'>
<span className='tw:loading tw:loading-spinner tw:loading-md'></span>
</div>
)}
</MapOverlayPage>
)

View File

@ -1,7 +1,9 @@
import { MapPinIcon } from '@heroicons/react/24/solid'
import { Link } from 'react-router-dom'
import { useAppState } from '#components/AppShell/hooks/useAppState'
import { useItems } from '#components/Map/hooks/useItems'
import { useReverseGeocode } from '#components/Map/hooks/useReverseGeocode'
import type { Item } from '#types/Item'
@ -13,6 +15,35 @@ interface Props {
hideWhenEmpty?: boolean
}
function RelationCard({ item }: { item: Item }) {
const appState = useAppState()
const avatar = item.image ? appState.assetsApi.url + item.image : null
const { address } = useReverseGeocode(
item.position?.coordinates as [number, number] | undefined,
true,
'municipality',
)
return (
<Link
to={item.id}
className='tw:flex tw:items-center tw:gap-3 tw:p-2 tw:rounded-lg tw:bg-base-200'
>
{avatar && (
<div className='tw:avatar'>
<div className='tw:w-12 tw:rounded-full'>
<img src={avatar} alt={item.name ?? ''} />
</div>
</div>
)}
<div className='tw:flex-1 tw:min-w-0'>
<div className='tw:font-bold tw:text-lg tw:truncate tw:text-base-content'>{item.name}</div>
</div>
</Link>
)
}
export const RelationsView = ({
item,
relation,
@ -21,7 +52,6 @@ export const RelationsView = ({
hideWhenEmpty = true,
}: Props) => {
const items = useItems()
const appState = useAppState()
if (!item.relations) return
@ -60,32 +90,16 @@ export const RelationsView = ({
}
return (
<div className='tw:my-10 tw:mt-2 tw:px-6'>
<h2 className='tw:text-lg tw:font-bold'>{heading}</h2>
<div className='tw:my-4 tw:px-6'>
<h2 className='tw:text-xl tw:font-bold tw:mb-3'>{heading}</h2>
{hasRelatedItems ? (
<ul>
<div className='tw:grid tw:grid-cols-1 tw:@sm:grid-cols-2 tw:@lg:grid-cols-3 tw:gap-2'>
{relatedItems.map((relatedItem) => (
<li key={relatedItem.id}>
<Link to={relatedItem.id} className='tw:flex tw:flex-row'>
<div>
{relatedItem.image ? (
<img
className='tw:size-10 tw:rounded-full'
src={appState.assetsApi.url + '/' + relatedItem.image}
/>
) : (
<div className='tw:size-10 tw:rounded-full tw:bg-gray-200' />
)}
</div>
<div className='tw:ml-2 tw:flex tw:items-center tw:min-h-[2.5rem]'>
<div>{relatedItem.name}</div>
</div>
</Link>
</li>
<RelationCard key={relatedItem.id} item={relatedItem} />
))}
</ul>
</div>
) : (
<p>No related items found.</p>
<p className='tw:text-base-content/70'>No related items found.</p>
)}
</div>
)