This commit is contained in:
silas
2021-12-11 16:28:42 +01:00
parent 34256d42ba
commit afb278ad87
39 changed files with 46423 additions and 5626 deletions

View 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} />;
});

View File

@@ -0,0 +1,5 @@
export type MemberType = {
id: string,
name: string,
usedForBalance?: boolean,
};

View 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}>&lt;</Button>
<Grow center>Woche {week + 1}</Grow>
<Button onClick={incrementWeek}>&gt;</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 };

View 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));

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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 };

View 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));