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 { UnderlineFeatureClient as UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
import { BoldFeatureClient as BoldFeatureClient_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 { 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 = {
|
export const importMap = {
|
||||||
"@payloadcms/richtext-lexical/rsc#RscEntryLexicalCell": RscEntryLexicalCell_44fe37237e0ebf4470c9990d8cb7b07e,
|
"@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#HeadingFeatureClient": HeadingFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
"@payloadcms/richtext-lexical/client#UnderlineFeatureClient": UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
"@payloadcms/richtext-lexical/client#UnderlineFeatureClient": UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
"@payloadcms/richtext-lexical/client#BoldFeatureClient": BoldFeatureClient_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'],
|
relationTo: ['event', 'blog', 'worship'],
|
||||||
admin: {
|
admin: {
|
||||||
allowCreate: false,
|
allowCreate: false,
|
||||||
allowEdit: false
|
allowEdit: false,
|
||||||
|
sortOptions: {
|
||||||
|
"event": "-createdAt",
|
||||||
|
"blog": "-createdAt",
|
||||||
|
"worship": "-date",
|
||||||
|
}
|
||||||
},
|
},
|
||||||
required: false
|
required: false
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -421,4 +421,6 @@ export const Logo = ({withText = false, color = "#000000", height = 75, textColo
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</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.
|
* 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 {
|
export interface Config {
|
||||||
auth: {
|
auth: {
|
||||||
users: UserAuthOperations;
|
users: UserAuthOperations;
|
||||||
};
|
};
|
||||||
|
blocks: {};
|
||||||
collections: {
|
collections: {
|
||||||
parish: Parish;
|
parish: Parish;
|
||||||
church: Church;
|
church: Church;
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,36 @@ const dirname = path.dirname(filename)
|
||||||
export default buildConfig({
|
export default buildConfig({
|
||||||
admin: {
|
admin: {
|
||||||
user: Users.slug,
|
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: [
|
collections: [
|
||||||
Parish,
|
Parish,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue