Hocks Mieterportal: 5 Module (Dashboard, Mietkonto, Schadensmeldungen, Dokumente, Nachrichten), Docker-Setup, eigenes Branding
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
import {
|
||||
createContext,
|
||||
useContext,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useReducer,
|
||||
type ReactNode,
|
||||
} from 'react'
|
||||
import type { Role, Ticket, Transaction, DocumentItem, Thread, Message } from '../types'
|
||||
import {
|
||||
units,
|
||||
transactions,
|
||||
tickets,
|
||||
documents,
|
||||
threads,
|
||||
announcements,
|
||||
DEMO_TENANT,
|
||||
DEMO_UNIT_ID,
|
||||
} from '../data/seed'
|
||||
|
||||
interface State {
|
||||
role: Role
|
||||
tickets: Ticket[]
|
||||
transactions: Transaction[]
|
||||
documents: DocumentItem[]
|
||||
threads: Thread[]
|
||||
}
|
||||
|
||||
type Action =
|
||||
| { type: 'setRole'; role: Role }
|
||||
| { type: 'addTicket'; ticket: Ticket }
|
||||
| { type: 'setTicketStatus'; id: string; status: Ticket['status'] }
|
||||
| {
|
||||
type: 'addMessage'
|
||||
threadId: string
|
||||
message: Message
|
||||
}
|
||||
| { type: 'newThread'; thread: Thread }
|
||||
| { type: 'markThreadRead'; threadId: string; role: Role }
|
||||
|
||||
const initialState: State = {
|
||||
role: 'tenant',
|
||||
tickets,
|
||||
transactions,
|
||||
documents,
|
||||
threads,
|
||||
}
|
||||
|
||||
const STORAGE_KEY = 'hocks-mieterportal-v1'
|
||||
|
||||
function loadState(): State {
|
||||
try {
|
||||
const raw = localStorage.getItem(STORAGE_KEY)
|
||||
if (raw) return { ...initialState, ...JSON.parse(raw) }
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
return initialState
|
||||
}
|
||||
|
||||
function reducer(state: State, action: Action): State {
|
||||
switch (action.type) {
|
||||
case 'setRole':
|
||||
return { ...state, role: action.role }
|
||||
case 'addTicket':
|
||||
return { ...state, tickets: [action.ticket, ...state.tickets] }
|
||||
case 'setTicketStatus':
|
||||
return {
|
||||
...state,
|
||||
tickets: state.tickets.map((t) =>
|
||||
t.id === action.id ? { ...t, status: action.status } : t,
|
||||
),
|
||||
}
|
||||
case 'addMessage':
|
||||
return {
|
||||
...state,
|
||||
threads: state.threads.map((th) =>
|
||||
th.id === action.threadId
|
||||
? {
|
||||
...th,
|
||||
unreadByAdmin: action.message.from === 'tenant',
|
||||
unreadByTenant: action.message.from === 'admin',
|
||||
messages: [...th.messages, action.message],
|
||||
}
|
||||
: th,
|
||||
),
|
||||
}
|
||||
case 'newThread':
|
||||
return { ...state, threads: [action.thread, ...state.threads] }
|
||||
case 'markThreadRead':
|
||||
return {
|
||||
...state,
|
||||
threads: state.threads.map((th) =>
|
||||
th.id === action.threadId
|
||||
? action.role === 'tenant'
|
||||
? { ...th, unreadByTenant: false }
|
||||
: { ...th, unreadByAdmin: false }
|
||||
: th,
|
||||
),
|
||||
}
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
interface Store extends State {
|
||||
dispatch: React.Dispatch<Action>
|
||||
demoUnit: typeof units[number]
|
||||
units: typeof units
|
||||
announcements: typeof announcements
|
||||
}
|
||||
|
||||
const StoreContext = createContext<Store | null>(null)
|
||||
|
||||
export function StoreProvider({ children }: { children: ReactNode }) {
|
||||
const [state, dispatch] = useReducer(reducer, undefined, loadState)
|
||||
|
||||
useEffect(() => {
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(state))
|
||||
}, [state])
|
||||
|
||||
const value = useMemo<Store>(
|
||||
() => ({
|
||||
...state,
|
||||
dispatch,
|
||||
demoUnit: units.find((u) => u.id === DEMO_UNIT_ID)!,
|
||||
units,
|
||||
announcements,
|
||||
}),
|
||||
[state],
|
||||
)
|
||||
|
||||
return <StoreContext.Provider value={value}>{children}</StoreContext.Provider>
|
||||
}
|
||||
|
||||
export function useStore(): Store {
|
||||
const ctx = useContext(StoreContext)
|
||||
if (!ctx) throw new Error('useStore außerhalb von StoreProvider')
|
||||
return ctx
|
||||
}
|
||||
|
||||
export const fmtEUR = new Intl.NumberFormat('de-DE', {
|
||||
style: 'currency',
|
||||
currency: 'EUR',
|
||||
})
|
||||
|
||||
export { DEMO_TENANT, DEMO_UNIT_ID }
|
||||
Reference in New Issue
Block a user