update
This commit is contained in:
67
src/client/ts/PrayerCircle/MemberList.tsx
Normal file
67
src/client/ts/PrayerCircle/MemberList.tsx
Normal file
@@ -0,0 +1,67 @@
|
||||
import * as React from 'react';
|
||||
import { FunctionComponent, useCallback } from 'react';
|
||||
import { HiddenInput, List } from 'react-bootstrap-mobile';
|
||||
import { useAppDispatch, useAppSelector } from '../Store/reduxHooks';
|
||||
import { removeMember, saveMember, selectMembers } from './prayerCircleSlice';
|
||||
import { MemberType } from './MemberType';
|
||||
import { nanoid } from '@reduxjs/toolkit';
|
||||
|
||||
type Props = {};
|
||||
|
||||
export const MemberList: FunctionComponent<Props> = React.memo(({}) => {
|
||||
// Variables
|
||||
const dispatch = useAppDispatch();
|
||||
const members = useAppSelector((state) => selectMembers(state));
|
||||
members.push({
|
||||
id: nanoid(),
|
||||
name: '',
|
||||
usedForBalance: false,
|
||||
});
|
||||
|
||||
// States
|
||||
|
||||
// Refs
|
||||
|
||||
// Callbacks
|
||||
const keyExtractor = useCallback((item: MemberType) => item.id ?? 'undefined', []);
|
||||
const saveChangedMember = useCallback(
|
||||
({ extraData: memberId, target: { value: name } }) => {
|
||||
if (name.trim() === '') {
|
||||
if (memberId) {
|
||||
dispatch(removeMember(memberId));
|
||||
}
|
||||
} else {
|
||||
dispatch(
|
||||
saveMember({
|
||||
id: memberId,
|
||||
name,
|
||||
})
|
||||
);
|
||||
}
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
// Effects
|
||||
|
||||
// Other
|
||||
|
||||
// Render Functions
|
||||
const renderMember = useCallback(
|
||||
(member: MemberType) => {
|
||||
return (
|
||||
<HiddenInput
|
||||
key={member.id}
|
||||
noFocusHint={true}
|
||||
value={member.name}
|
||||
placeholder="+ Add Person"
|
||||
onChange={saveChangedMember}
|
||||
onChangeData={member.id}
|
||||
/>
|
||||
);
|
||||
},
|
||||
[saveChangedMember]
|
||||
);
|
||||
|
||||
return <List items={members} renderItem={renderMember} keyExtractor={keyExtractor} />;
|
||||
});
|
||||
5
src/client/ts/PrayerCircle/MemberType.ts
Normal file
5
src/client/ts/PrayerCircle/MemberType.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export type MemberType = {
|
||||
id: string,
|
||||
name: string,
|
||||
usedForBalance?: boolean,
|
||||
};
|
||||
135
src/client/ts/PrayerCircle/PartnerTable.tsx
Normal file
135
src/client/ts/PrayerCircle/PartnerTable.tsx
Normal file
@@ -0,0 +1,135 @@
|
||||
import * as React from 'react';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useAppDispatch, useAppSelector } from '../Store/reduxHooks';
|
||||
import { selectMemberIds, setWeek } from './prayerCircleSlice';
|
||||
import { Button, Flex, Grow, Table } from 'react-bootstrap-mobile';
|
||||
import { PrayerCircleCalculator } from './PrayerCircleCalculator';
|
||||
|
||||
export type PartnerTableProps = {};
|
||||
|
||||
function PartnerTable({}: PartnerTableProps) {
|
||||
// Variables
|
||||
const membersIds = useAppSelector((state) => selectMemberIds(state));
|
||||
const members = useAppSelector((state) => state.prayerCircle.members);
|
||||
const week = useAppSelector((state) => state.prayerCircle.week ?? 0);
|
||||
const useWeekdays = useAppSelector((state) => state.prayerCircle.useWeekdays);
|
||||
const usePartners = useAppSelector((state) => state.prayerCircle.usePartners);
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const columnsWeek = useMemo(
|
||||
() => [
|
||||
{
|
||||
Header: 'Partner 1',
|
||||
accessor: 'partner1', // accessor is the "key" in the data
|
||||
},
|
||||
{
|
||||
Header: 'Partner 2',
|
||||
accessor: 'partner2',
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
||||
const columnsWeekdays = useMemo(
|
||||
() => [
|
||||
{
|
||||
Header: 'Person',
|
||||
accessor: 'person', // accessor is the "key" in the data
|
||||
},
|
||||
{
|
||||
Header: 'Mo',
|
||||
accessor: 'day0',
|
||||
},
|
||||
{
|
||||
Header: 'Di',
|
||||
accessor: 'day1',
|
||||
},
|
||||
{
|
||||
Header: 'Mi',
|
||||
accessor: 'day2',
|
||||
},
|
||||
{
|
||||
Header: 'Do',
|
||||
accessor: 'day3',
|
||||
},
|
||||
{
|
||||
Header: 'Fr',
|
||||
accessor: 'day4',
|
||||
},
|
||||
{
|
||||
Header: 'Sa',
|
||||
accessor: 'day5',
|
||||
},
|
||||
{
|
||||
Header: 'So',
|
||||
accessor: 'day6',
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
||||
// States
|
||||
|
||||
// Refs
|
||||
|
||||
// Callbacks
|
||||
const incrementWeek = useCallback(() => dispatch(setWeek(week + 1)), [week, dispatch]);
|
||||
const decrementWeek = useCallback(() => dispatch(setWeek(week - 1)), [week, dispatch]);
|
||||
|
||||
// Effects
|
||||
|
||||
// Other
|
||||
const partnerTable = useMemo(
|
||||
() => PrayerCircleCalculator.generateTableFor(membersIds, usePartners),
|
||||
[membersIds, usePartners]
|
||||
);
|
||||
|
||||
if (!partnerTable || membersIds.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const partnerTableNames = partnerTable.map((partnerColumn) => {
|
||||
return Object.keys(partnerColumn).map((id) => {
|
||||
const name = members[id]?.name ?? id;
|
||||
const partnerName = members[partnerColumn[id]]?.name ?? partnerColumn[id];
|
||||
return [name, partnerName];
|
||||
}) as [string, string][];
|
||||
});
|
||||
|
||||
let data: Record<string, string>[] = [];
|
||||
if (!useWeekdays) {
|
||||
const column = partnerTableNames[week % partnerTableNames.length];
|
||||
data = column.map(([name1, name2]) => ({
|
||||
partner1: name1,
|
||||
partner2: name2,
|
||||
}));
|
||||
} else {
|
||||
data = [];
|
||||
for (let i = 0; i < 7; i++) {
|
||||
const column = partnerTableNames[(week * 7 + i) % partnerTableNames.length];
|
||||
column.forEach(([name1, name2], index) => {
|
||||
if (!data[index]) {
|
||||
data[index] = { person: name1 };
|
||||
}
|
||||
data[index][`day${i}`] = name2;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const columns = useWeekdays ? columnsWeekdays : columnsWeek;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Flex>
|
||||
<Button onClick={decrementWeek}><</Button>
|
||||
<Grow center>Woche {week + 1}</Grow>
|
||||
<Button onClick={incrementWeek}>></Button>
|
||||
</Flex>
|
||||
{/* <List renderItem={renderPartnerPaar} keyExtractor={partnerKeyExtractor} items={partners}/> */}
|
||||
<Table data={data} columns={columns} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const tmp = React.memo(PartnerTable) as typeof PartnerTable;
|
||||
export { tmp as PartnerTable };
|
||||
64
src/client/ts/PrayerCircle/PrayerCircle.tsx
Normal file
64
src/client/ts/PrayerCircle/PrayerCircle.tsx
Normal file
@@ -0,0 +1,64 @@
|
||||
import * as React from 'react';
|
||||
import { Sites, useSites, useTopBar } from 'cordova-sites';
|
||||
import { useState } from 'react';
|
||||
import { MemberList } from './MemberList';
|
||||
import { Settings } from '../Settings/Settings';
|
||||
import { Card } from 'react-bootstrap-mobile';
|
||||
import { PartnerTable } from './PartnerTable';
|
||||
import { Col, Row } from 'react-bootstrap';
|
||||
import { PrayerCircleSettings } from './PrayercircleSettings';
|
||||
|
||||
export type PrayerCircleProps = {};
|
||||
|
||||
function PrayerCircle({}: PrayerCircleProps) {
|
||||
// Variables
|
||||
const sites = useSites();
|
||||
|
||||
// States
|
||||
|
||||
// Refs
|
||||
|
||||
// Callbacks
|
||||
|
||||
// Effects
|
||||
useTopBar({
|
||||
title: 'Prayercircle',
|
||||
rightButtons: [
|
||||
{
|
||||
title: 'Settings',
|
||||
action: () => {
|
||||
sites?.startSite(Settings);
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// Other
|
||||
|
||||
// Render Functions
|
||||
|
||||
return (
|
||||
<>
|
||||
<Row lg={2} sm={1}>
|
||||
<Col>
|
||||
<Card fullHeight={true}>
|
||||
<PrayerCircleSettings />
|
||||
</Card>
|
||||
</Col>
|
||||
<Col className="order-lg-first">
|
||||
<Card noPaddingHeight={true}>
|
||||
<MemberList />
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
<Card>
|
||||
<PartnerTable />
|
||||
</Card>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const tmp = React.memo(PrayerCircle) as typeof PrayerCircle;
|
||||
export { tmp as PrayerCircle };
|
||||
|
||||
Sites.addInitialization((app) => app.addDeepLink('/PrayerCircle', tmp));
|
||||
4406
src/client/ts/PrayerCircle/PrayerCircleCalculator.ts
Normal file
4406
src/client/ts/PrayerCircle/PrayerCircleCalculator.ts
Normal file
File diff suppressed because it is too large
Load Diff
9249
src/client/ts/PrayerCircle/PrayerCircleCalculator_old.ts
Normal file
9249
src/client/ts/PrayerCircle/PrayerCircleCalculator_old.ts
Normal file
File diff suppressed because it is too large
Load Diff
41
src/client/ts/PrayerCircle/PrayercircleSettings.tsx
Normal file
41
src/client/ts/PrayerCircle/PrayercircleSettings.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
import * as React from 'react';
|
||||
import { Checkbox, Switch } from 'react-bootstrap-mobile';
|
||||
import { useCallback } from 'react';
|
||||
import { useAppDispatch, useAppSelector } from '../Store/reduxHooks';
|
||||
import { setUsePartners, setUseWeekdays } from './prayerCircleSlice';
|
||||
|
||||
export type PrayerCircleSettingsProps = {};
|
||||
|
||||
function PrayerCircleSettings({}: PrayerCircleSettingsProps) {
|
||||
// Variables
|
||||
const dispatch = useAppDispatch();
|
||||
const useWeekdays = useAppSelector((store) => store.prayerCircle.useWeekdays ?? false);
|
||||
const usePartners = useAppSelector((store) => store.prayerCircle.usePartners ?? true);
|
||||
|
||||
// States
|
||||
|
||||
// Refs
|
||||
|
||||
// Callbacks
|
||||
const onChangeUseWeekdays = useCallback(({ target: { checked } }) => dispatch(setUseWeekdays(checked)), [dispatch]);
|
||||
const onChangeUsePartners = useCallback(({ target: { checked } }) => dispatch(setUsePartners(checked)), [dispatch]);
|
||||
|
||||
// Effects
|
||||
|
||||
// Other
|
||||
|
||||
// Render Functions
|
||||
|
||||
return (
|
||||
<>
|
||||
<Switch preLabel="Kette" onChange={onChangeUsePartners} checked={usePartners}>
|
||||
Partner
|
||||
</Switch>
|
||||
<br />
|
||||
<Checkbox label="Benutze Wochentage" checked={useWeekdays} onChange={onChangeUseWeekdays} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const tmp = React.memo(PrayerCircleSettings) as typeof PrayerCircleSettings;
|
||||
export { tmp as PrayerCircleSettings };
|
||||
38
src/client/ts/PrayerCircle/prayerCircleSlice.ts
Normal file
38
src/client/ts/PrayerCircle/prayerCircleSlice.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
||||
import { MemberType } from './MemberType';
|
||||
import memoize from 'proxy-memoize';
|
||||
import type { StoreState } from '../Store/store';
|
||||
|
||||
export const prayerCircleSlice = createSlice({
|
||||
name: 'prayerCircle',
|
||||
initialState: {
|
||||
members: {} as Record<string, MemberType>,
|
||||
week: 0,
|
||||
useWeekdays: false,
|
||||
usePartners: true,
|
||||
},
|
||||
reducers: {
|
||||
saveMember: (state, action: PayloadAction<MemberType>) => {
|
||||
const member = action.payload;
|
||||
state.members[member.id] = member;
|
||||
},
|
||||
removeMember: (state, { payload: memberId }: PayloadAction<string>) => {
|
||||
delete state.members[memberId];
|
||||
},
|
||||
setWeek: (state, { payload: week }: PayloadAction<number>) => {
|
||||
state.week = week;
|
||||
},
|
||||
setUseWeekdays: (state, { payload: useWeekdays }: PayloadAction<boolean>) => {
|
||||
state.useWeekdays = useWeekdays;
|
||||
},
|
||||
setUsePartners: (state, { payload: usePartners }: PayloadAction<boolean>) => {
|
||||
state.usePartners = usePartners;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { saveMember, removeMember, setWeek, setUseWeekdays, setUsePartners } = prayerCircleSlice.actions;
|
||||
export const { reducer: prayerCircle } = prayerCircleSlice;
|
||||
|
||||
export const selectMembers = memoize((state: StoreState) => Object.values(state.prayerCircle.members));
|
||||
export const selectMemberIds = memoize((state: StoreState) => Object.keys(state.prayerCircle.members));
|
||||
Reference in New Issue
Block a user