feature: add worship per week
This commit is contained in:
parent
3faa2a2672
commit
e75b6609c3
14 changed files with 393 additions and 3 deletions
40
src/admin/components/calendar/Calendar.tsx
Normal file
40
src/admin/components/calendar/Calendar.tsx
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
'use client'
|
||||
|
||||
import { useEffect, useState } from 'react'
|
||||
import moment from 'moment'
|
||||
import Day from '@/admin/components/calendar/Day'
|
||||
|
||||
|
||||
const Calendar = () => {
|
||||
const weekNr = moment().isoWeek();
|
||||
const [week, setWeek] = useState(weekNr.toString())
|
||||
const [days, setDays] = useState<string[]>([])
|
||||
|
||||
// on week change => sey days
|
||||
useEffect(() => {
|
||||
const date = moment().isoWeek(Number(week));
|
||||
const newDays = [];
|
||||
|
||||
for(let i=0; i<7; i++) {
|
||||
let day = date.weekday(i).toISOString();
|
||||
newDays.push(day)
|
||||
}
|
||||
|
||||
setDays(newDays)
|
||||
}, [week, setDays])
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div>
|
||||
<select value={week} onChange={e => setWeek(e.currentTarget.value)}>
|
||||
{[...Array(51).keys()].map(i => <option key={i} value={i.toString()}>Woche {i}</option>)}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
||||
{days.map(day => <Day key={day} date={day} mass={[]} />)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Calendar
|
||||
22
src/admin/components/calendar/ChurchSelect/ChurchSelect.tsx
Normal file
22
src/admin/components/calendar/ChurchSelect/ChurchSelect.tsx
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import { useSyncExternalStore } from 'react'
|
||||
import { churchStore } from '@/admin/components/calendar/ChurchSelect/churchStore'
|
||||
|
||||
type ChurchSelectProps = {
|
||||
value: string,
|
||||
className?: string,
|
||||
onChange: (value: string) => void,
|
||||
}
|
||||
|
||||
export const ChurchSelect = ({value, onChange, className}: ChurchSelectProps) => {
|
||||
const churches = useSyncExternalStore(churchStore.subscribe, churchStore.getSnapshot)
|
||||
|
||||
return (
|
||||
<select
|
||||
className={className}
|
||||
value={value}
|
||||
onChange={e => onChange(e.target.value)}
|
||||
>
|
||||
{churches.map(c => <option key={c.id} value={c.id}>{c.name}</option>)}
|
||||
</select>
|
||||
)
|
||||
}
|
||||
42
src/admin/components/calendar/ChurchSelect/churchStore.ts
Normal file
42
src/admin/components/calendar/ChurchSelect/churchStore.ts
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import { fetchChurches } from '@/fetch/churches'
|
||||
|
||||
type Church = {
|
||||
id: string,
|
||||
name: string
|
||||
}
|
||||
|
||||
let churches: Church[] = [];
|
||||
const listeners = new Set<() => void>();
|
||||
|
||||
/**
|
||||
* ChurchStore to use with Reacts `useSyncExternalStore`
|
||||
*/
|
||||
export const churchStore = {
|
||||
// fetch all churches from API
|
||||
async init() {
|
||||
const data = await fetchChurches();
|
||||
|
||||
if (data) {
|
||||
churches = data.docs.map(c => {
|
||||
return { id: c.id, name: c.name }
|
||||
});
|
||||
|
||||
emitChange()
|
||||
}
|
||||
},
|
||||
subscribe: (listener: () => void) => {
|
||||
listeners.add(listener);
|
||||
return () => listeners.delete(listener);
|
||||
},
|
||||
getSnapshot() {
|
||||
return churches;
|
||||
}
|
||||
}
|
||||
|
||||
function emitChange() {
|
||||
for (let listener of listeners) {
|
||||
listener();
|
||||
}
|
||||
}
|
||||
|
||||
await churchStore.init();
|
||||
36
src/admin/components/calendar/Day.tsx
Normal file
36
src/admin/components/calendar/Day.tsx
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import { liturgicalDayName } from '@/hooks/liturgicalDayName'
|
||||
import styles from "./styles.module.scss"
|
||||
import MassForm from '@/admin/components/calendar/MassForm'
|
||||
|
||||
type DayProps = {
|
||||
date: string,
|
||||
mass: Mass[]
|
||||
}
|
||||
|
||||
type Mass = {
|
||||
id: string,
|
||||
|
||||
}
|
||||
|
||||
export const Day = ({date}: DayProps) => {
|
||||
const dayName = liturgicalDayName(date)
|
||||
const dateObj = new Date(date);
|
||||
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.day}>
|
||||
<strong>{dateObj.toLocaleDateString("de-De", {weekday: "long"})}</strong> <br/>
|
||||
{dayName}
|
||||
</div>
|
||||
<div className={styles.date}>
|
||||
{date.substring(8, 10)}
|
||||
</div>
|
||||
<div>
|
||||
<MassForm />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Day
|
||||
54
src/admin/components/calendar/MassForm.tsx
Normal file
54
src/admin/components/calendar/MassForm.tsx
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
import styles from "./form.module.scss"
|
||||
import { ChurchSelect } from '@/admin/components/calendar/ChurchSelect/ChurchSelect'
|
||||
|
||||
const MassForm = () => {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.time}>
|
||||
<div className={styles.formRow}>
|
||||
<select name="time" className={styles.select}>
|
||||
<option>10:00 Uhr</option>
|
||||
<option>20:00 Uhr</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<ChurchSelect
|
||||
className={styles.select}
|
||||
value={"23"}
|
||||
onChange={() => console.log("chage")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
<div className={styles.formRow}>
|
||||
<input type="radio" id="heilige_messe" name="massType" value="Heilige Messe" required />
|
||||
<label htmlFor="heilige_messe">Heilige Messe</label>
|
||||
|
||||
<input type="radio" id="wort_gottes_feier" name="massType" value="Wort-Gottes-Feier" required />
|
||||
<label htmlFor="wort_gottes_feier">Wort-Gottes-Feier</label>
|
||||
|
||||
<input type="radio" id="familienmesse" name="massType" value="Familienmesse" required />
|
||||
<label htmlFor="familienmesse">Familienmesse</label>
|
||||
</div>
|
||||
|
||||
<div className={styles.formRow}>
|
||||
<input type="text" id="title" name="title" placeholder={"Titel"} className={styles.input} required />
|
||||
</div>
|
||||
<div className={styles.formRow}>
|
||||
<input type="text" id="celebrant" name="celebrant" placeholder={"Zelebrant"} className={styles.input}/>
|
||||
</div>
|
||||
<div className={styles.formRow}>
|
||||
<textarea id="description" name="description" placeholder={"Hinweise"} className={styles.input} rows={4}></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button>Entfernen</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default MassForm
|
||||
30
src/admin/components/calendar/form.module.scss
Normal file
30
src/admin/components/calendar/form.module.scss
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
.container {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.time {
|
||||
width: 130px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.formRow {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.input {
|
||||
font-size: 12px;
|
||||
padding: 3px;
|
||||
width: 350px;
|
||||
border: 1px solid #ababab;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.select {
|
||||
font-size: 12px;
|
||||
padding: 3px;
|
||||
border: 1px solid #ababab;
|
||||
border-radius: 4px;
|
||||
width: 100px;
|
||||
background-color: #ffffff;
|
||||
font-family: inherit;
|
||||
}
|
||||
13
src/admin/components/calendar/styles.module.scss
Normal file
13
src/admin/components/calendar/styles.module.scss
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
.container {
|
||||
display: flex;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.day {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.date {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
40
src/admin/components/test/TestView.tsx
Normal file
40
src/admin/components/test/TestView.tsx
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import { Gutter } from '@payloadcms/ui'
|
||||
import { DefaultTemplate } from '@payloadcms/next/templates'
|
||||
import { AdminViewServerProps } from 'payload'
|
||||
import Calendar from '@/admin/components/calendar/Calendar'
|
||||
|
||||
export default function TestPage({
|
||||
initPageResult,
|
||||
params,
|
||||
searchParams,
|
||||
}: AdminViewServerProps) {
|
||||
const {
|
||||
req: {
|
||||
user
|
||||
}
|
||||
} = initPageResult
|
||||
|
||||
if (!user) {
|
||||
return <p>You must be logged in to view this page.</p>
|
||||
}
|
||||
|
||||
return (
|
||||
<DefaultTemplate
|
||||
i18n={initPageResult.req.i18n}
|
||||
locale={initPageResult.locale}
|
||||
params={params}
|
||||
payload={initPageResult.req.payload}
|
||||
permissions={initPageResult.permissions}
|
||||
searchParams={searchParams}
|
||||
user={initPageResult.req.user || undefined}
|
||||
visibleEntities={initPageResult.visibleEntities}
|
||||
>
|
||||
<Gutter>
|
||||
<h1>Gottesdiensten</h1>
|
||||
<p>This view uses the Default Template.</p>
|
||||
|
||||
<Calendar />
|
||||
</Gutter>
|
||||
</DefaultTemplate>
|
||||
)
|
||||
}
|
||||
|
|
@ -9,6 +9,8 @@ import { HeadingFeatureClient as HeadingFeatureClient_e70f5e05f09f93e00b997edb1e
|
|||
import { UnderlineFeatureClient as UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||
import { BoldFeatureClient as BoldFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||
import { ItalicFeatureClient as ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||
import { default as default_9bcae99938dc292be0063ce32055e14c } from 'src/components/Logo/Logo'
|
||||
import { default as default_da280595b8aff80d788c3701c6162e87 } from 'src/admin/components/test/TestView'
|
||||
|
||||
export const importMap = {
|
||||
"@payloadcms/richtext-lexical/rsc#RscEntryLexicalCell": RscEntryLexicalCell_44fe37237e0ebf4470c9990d8cb7b07e,
|
||||
|
|
@ -21,5 +23,7 @@ export const importMap = {
|
|||
"@payloadcms/richtext-lexical/client#HeadingFeatureClient": HeadingFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#UnderlineFeatureClient": UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#BoldFeatureClient": BoldFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#ItalicFeatureClient": ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864
|
||||
"@payloadcms/richtext-lexical/client#ItalicFeatureClient": ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"/components/Logo/Logo#default": default_9bcae99938dc292be0063ce32055e14c,
|
||||
"/admin/components/test/TestView#default": default_da280595b8aff80d788c3701c6162e87
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,12 @@ export const Highlight: CollectionConfig = {
|
|||
relationTo: ['event', 'blog', 'worship'],
|
||||
admin: {
|
||||
allowCreate: false,
|
||||
allowEdit: false
|
||||
allowEdit: false,
|
||||
sortOptions: {
|
||||
"event": "-createdAt",
|
||||
"blog": "-createdAt",
|
||||
"worship": "-date",
|
||||
}
|
||||
},
|
||||
required: false
|
||||
},
|
||||
|
|
|
|||
|
|
@ -422,3 +422,5 @@ export const Logo = ({withText = false, color = "#000000", height = 75, textColo
|
|||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default Logo
|
||||
17
src/fetch/churches.ts
Normal file
17
src/fetch/churches.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { Church } from '@/payload-types'
|
||||
import { PaginatedDocs } from 'payload'
|
||||
import { stringify } from 'qs-esm'
|
||||
|
||||
export const fetchChurches = async (): Promise<PaginatedDocs<Church> | undefined> => {
|
||||
const stringifiedQuery = stringify(
|
||||
{
|
||||
sort: "name",
|
||||
limit: 50
|
||||
},
|
||||
{ addQueryPrefix: true },
|
||||
)
|
||||
|
||||
const resp = await fetch(`http://localhost:3000/api/church`);
|
||||
if (!resp.ok) return undefined;
|
||||
return resp.json();
|
||||
}
|
||||
|
|
@ -6,10 +6,65 @@
|
|||
* and re-run `payload generate:types` to regenerate this file.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Supported timezones in IANA format.
|
||||
*
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "supportedTimezones".
|
||||
*/
|
||||
export type SupportedTimezones =
|
||||
| 'Pacific/Midway'
|
||||
| 'Pacific/Niue'
|
||||
| 'Pacific/Honolulu'
|
||||
| 'Pacific/Rarotonga'
|
||||
| 'America/Anchorage'
|
||||
| 'Pacific/Gambier'
|
||||
| 'America/Los_Angeles'
|
||||
| 'America/Tijuana'
|
||||
| 'America/Denver'
|
||||
| 'America/Phoenix'
|
||||
| 'America/Chicago'
|
||||
| 'America/Guatemala'
|
||||
| 'America/New_York'
|
||||
| 'America/Bogota'
|
||||
| 'America/Caracas'
|
||||
| 'America/Santiago'
|
||||
| 'America/Buenos_Aires'
|
||||
| 'America/Sao_Paulo'
|
||||
| 'Atlantic/South_Georgia'
|
||||
| 'Atlantic/Azores'
|
||||
| 'Atlantic/Cape_Verde'
|
||||
| 'Europe/London'
|
||||
| 'Europe/Berlin'
|
||||
| 'Africa/Lagos'
|
||||
| 'Europe/Athens'
|
||||
| 'Africa/Cairo'
|
||||
| 'Europe/Moscow'
|
||||
| 'Asia/Riyadh'
|
||||
| 'Asia/Dubai'
|
||||
| 'Asia/Baku'
|
||||
| 'Asia/Karachi'
|
||||
| 'Asia/Tashkent'
|
||||
| 'Asia/Calcutta'
|
||||
| 'Asia/Dhaka'
|
||||
| 'Asia/Almaty'
|
||||
| 'Asia/Jakarta'
|
||||
| 'Asia/Bangkok'
|
||||
| 'Asia/Shanghai'
|
||||
| 'Asia/Singapore'
|
||||
| 'Asia/Tokyo'
|
||||
| 'Asia/Seoul'
|
||||
| 'Australia/Sydney'
|
||||
| 'Pacific/Guam'
|
||||
| 'Pacific/Noumea'
|
||||
| 'Pacific/Auckland'
|
||||
| 'Pacific/Fiji';
|
||||
|
||||
export interface Config {
|
||||
auth: {
|
||||
users: UserAuthOperations;
|
||||
};
|
||||
blocks: {};
|
||||
collections: {
|
||||
parish: Parish;
|
||||
church: Church;
|
||||
|
|
|
|||
|
|
@ -42,6 +42,36 @@ const dirname = path.dirname(filename)
|
|||
export default buildConfig({
|
||||
admin: {
|
||||
user: Users.slug,
|
||||
meta: {
|
||||
title: 'Dashboard',
|
||||
titleSuffix: '- Heilige Drei Könige'
|
||||
},
|
||||
importMap: {
|
||||
baseDir: dirname,
|
||||
},
|
||||
components: {
|
||||
views: {
|
||||
testCustomView: {
|
||||
Component: '/admin/components/test/TestView',
|
||||
path: '/test'
|
||||
},
|
||||
},
|
||||
graphics: {
|
||||
Logo: {
|
||||
path: '/components/Logo/Logo',
|
||||
serverProps: {
|
||||
withText: true,
|
||||
height: 90
|
||||
}
|
||||
},
|
||||
Icon: {
|
||||
path: '/components/Logo/Logo',
|
||||
serverProps: {
|
||||
height: 18
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
collections: [
|
||||
Parish,
|
||||
|
|
|
|||
Loading…
Reference in a new issue