This commit is contained in:
silas 2021-12-12 18:06:33 +01:00
parent afb278ad87
commit 7611c41c67
9 changed files with 171 additions and 9412 deletions

View File

@ -9,7 +9,7 @@
<meta name="viewport" content="initial-scale=1, width=device-width, viewport-fit=cover"> <meta name="viewport" content="initial-scale=1, width=device-width, viewport-fit=cover">
<meta name="color-scheme" content="light dark"> <meta name="color-scheme" content="light dark">
<!-- <link rel="stylesheet" href="css/index.css">--> <!-- <link rel="stylesheet" href="css/index.css">-->
<title>Hello World</title> <title>PrayerCircle</title>
</head> </head>
<!--<body class="flat-design">--> <!--<body class="flat-design">-->
<body class="material-design"> <body class="material-design">

View File

@ -2,7 +2,7 @@ import * as React from 'react';
import { useCallback, useMemo } from 'react'; import { useCallback, useMemo } from 'react';
import { useAppDispatch, useAppSelector } from '../Store/reduxHooks'; import { useAppDispatch, useAppSelector } from '../Store/reduxHooks';
import { selectMemberIds, setWeek } from './prayerCircleSlice'; import { selectMemberIds, setWeek } from './prayerCircleSlice';
import { Button, Flex, Grow, Table } from 'react-bootstrap-mobile'; import { Body, Button, Column, ColumnCellData, Flex, Grow, Table } from 'react-bootstrap-mobile';
import { PrayerCircleCalculator } from './PrayerCircleCalculator'; import { PrayerCircleCalculator } from './PrayerCircleCalculator';
export type PartnerTableProps = {}; export type PartnerTableProps = {};
@ -16,8 +16,8 @@ function PartnerTable({}: PartnerTableProps) {
const usePartners = useAppSelector((state) => state.prayerCircle.usePartners); const usePartners = useAppSelector((state) => state.prayerCircle.usePartners);
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const columnsWeek = useMemo( const columnsWeek = useMemo(() => {
() => [ const columns: Column<string> = [
{ {
Header: 'Partner 1', Header: 'Partner 1',
accessor: 'partner1', // accessor is the "key" in the data accessor: 'partner1', // accessor is the "key" in the data
@ -25,13 +25,55 @@ function PartnerTable({}: PartnerTableProps) {
{ {
Header: 'Partner 2', Header: 'Partner 2',
accessor: 'partner2', accessor: 'partner2',
width: '50%',
}, },
], ];
[] if (!usePartners) {
); columns.splice(1, 0, {
Header: '',
id: 'prayingTitles',
Cell: () => (
<>
<Body block={true}>Ich bete für</Body>
<Body block={true} prio="secondary" size="small">
Für mich betet
</Body>
</>
),
});
// columns[0].Cell = (cellData: ColumnCellData<string>) => {
// const partner = cellData.value;
// console.log('cellData', cellData);
// return (
// <div>
// <Body>{partner}</Body>
// <span>
// {/* <Body>Ich bete für</Body> */}
// <Body prio="secondary" size="small">
// Für mich betet
// </Body>
// </span>
// </div>
// );
// };
const columnsWeekdays = useMemo( columns[2].Cell = ({ cell: { column, row }, value: partner }: ColumnCellData<string>) => {
() => [ const other = row.original[`${column.id}Other`];
return (
<>
<Body block={true}>{partner}</Body>
<Body block={true} prio="secondary" size="small">
{other}
</Body>
</>
);
};
}
return columns;
}, [usePartners]);
const columnsWeekdays = useMemo(() => {
const columns: Column<string> = [
{ {
Header: 'Person', Header: 'Person',
accessor: 'person', // accessor is the "key" in the data accessor: 'person', // accessor is the "key" in the data
@ -64,9 +106,44 @@ function PartnerTable({}: PartnerTableProps) {
Header: 'So', Header: 'So',
accessor: 'day6', accessor: 'day6',
}, },
], ];
[] if (!usePartners) {
columns[0].Cell = ({ value: partner }: ColumnCellData<string>) => {
return (
<Flex>
<Grow>{partner}</Grow>
<Grow>
<Body block={true}>Ich bete für</Body>
<Body block={true} prio="secondary" size="small">
Für mich betet
</Body>
</Grow>
</Flex>
); );
};
const renderFunction = (cellData: ColumnCellData<string>) => {
const partner = cellData.value;
const other = cellData.cell.row.original[`${cellData.cell.column.id}Other`];
return (
<>
<Body block={true}>{partner}</Body>
<Body block={true} prio="secondary" size="small">
{other}
</Body>
</>
);
};
columns[1].Cell = renderFunction;
columns[2].Cell = renderFunction;
columns[3].Cell = renderFunction;
columns[4].Cell = renderFunction;
columns[5].Cell = renderFunction;
columns[6].Cell = renderFunction;
columns[7].Cell = renderFunction;
}
return columns;
}, [usePartners]);
// States // States
@ -79,45 +156,53 @@ function PartnerTable({}: PartnerTableProps) {
// Effects // Effects
// Other // Other
const partnerTable = useMemo( const [partnerTable, invertedPartnerTable] = useMemo(
() => PrayerCircleCalculator.generateTableFor(membersIds, usePartners), () => PrayerCircleCalculator.generateTableFor(membersIds, usePartners),
[membersIds, usePartners] [membersIds, usePartners]
); );
if (!partnerTable || membersIds.length === 0) { if (!partnerTable || !invertedPartnerTable || membersIds.length === 0) {
return null; return null;
} }
const partnerTableNames = partnerTable.map((partnerColumn) => { // console.log(partnerTable, invertedPartnerTable);
const partnerTableNames = partnerTable.map((partnerColumn, index) => {
return Object.keys(partnerColumn).map((id) => { return Object.keys(partnerColumn).map((id) => {
const name = members[id]?.name ?? id; const name = members[id]?.name ?? id;
const partnerName = members[partnerColumn[id]]?.name ?? partnerColumn[id]; const partnerName = members[partnerColumn[id]]?.name ?? partnerColumn[id];
return [name, partnerName]; const otherPartnerName = members[invertedPartnerTable[index][id]]?.name ?? invertedPartnerTable[index][id];
}) as [string, string][]; return [name, partnerName, otherPartnerName];
}) as [string, string, string][];
}); });
let data: Record<string, string>[] = []; let data: Record<string, string>[] = [];
if (!useWeekdays) { if (!useWeekdays) {
const column = partnerTableNames[week % partnerTableNames.length]; const column = partnerTableNames[week % partnerTableNames.length];
data = column.map(([name1, name2]) => ({ data = column.map(([name1, name2, name3]) => ({
partner1: name1, partner1: name1,
partner2: name2, partner2: name2,
partner2Other: name3,
})); }));
} else { } else {
data = []; data = [];
for (let i = 0; i < 7; i++) { for (let i = 0; i < 7; i++) {
const column = partnerTableNames[(week * 7 + i) % partnerTableNames.length]; const colIndex = (week * 7 + i) % partnerTableNames.length;
column.forEach(([name1, name2], index) => { const column = partnerTableNames[colIndex];
column.forEach(([person, partner1, partner2], index) => {
if (!data[index]) { if (!data[index]) {
data[index] = { person: name1 }; data[index] = { person };
} }
data[index][`day${i}`] = name2; data[index][`day${i}`] = partner1;
data[index][`day${i}Other`] = partner2;
}); });
} }
} }
const columns = useWeekdays ? columnsWeekdays : columnsWeek; const columns = useWeekdays ? columnsWeekdays : columnsWeek;
// Render Functions
return ( return (
<> <>
<Flex> <Flex>

View File

@ -1,8 +1,6 @@
import * as React from 'react'; import * as React from 'react';
import { Sites, useSites, useTopBar } from 'cordova-sites'; import { Sites, useTopBar } from 'cordova-sites';
import { useState } from 'react';
import { MemberList } from './MemberList'; import { MemberList } from './MemberList';
import { Settings } from '../Settings/Settings';
import { Card } from 'react-bootstrap-mobile'; import { Card } from 'react-bootstrap-mobile';
import { PartnerTable } from './PartnerTable'; import { PartnerTable } from './PartnerTable';
import { Col, Row } from 'react-bootstrap'; import { Col, Row } from 'react-bootstrap';
@ -12,7 +10,6 @@ export type PrayerCircleProps = {};
function PrayerCircle({}: PrayerCircleProps) { function PrayerCircle({}: PrayerCircleProps) {
// Variables // Variables
const sites = useSites();
// States // States
@ -23,14 +20,6 @@ function PrayerCircle({}: PrayerCircleProps) {
// Effects // Effects
useTopBar({ useTopBar({
title: 'Prayercircle', title: 'Prayercircle',
rightButtons: [
{
title: 'Settings',
action: () => {
sites?.startSite(Settings);
},
},
],
}); });
// Other // Other
@ -39,13 +28,13 @@ function PrayerCircle({}: PrayerCircleProps) {
return ( return (
<> <>
<Row lg={2} sm={1}> <Row lg={3} md={2} sm={1}>
<Col> <Col>
<Card fullHeight={true}> <Card fullHeight={true}>
<PrayerCircleSettings /> <PrayerCircleSettings />
</Card> </Card>
</Col> </Col>
<Col className="order-lg-first"> <Col className="order-md-first" md={6} lg={8}>
<Card noPaddingHeight={true}> <Card noPaddingHeight={true}>
<MemberList /> <MemberList />
</Card> </Card>

View File

@ -4251,9 +4251,12 @@ export class PrayerCircleCalculator {
console.log('TABLES', JSON.stringify(tables)); console.log('TABLES', JSON.stringify(tables));
} }
static generateTableFor(memberIds: string[], usePartners = true) { static generateTableFor(
memberIds: string[],
usePartners = true
): [false, false] | [Record<string, string>[], Record<string, string>[]] {
if (memberIds.length === 0) { if (memberIds.length === 0) {
return []; return [[], []];
} }
memberIds = memberIds.slice(); memberIds = memberIds.slice();
@ -4269,15 +4272,11 @@ export class PrayerCircleCalculator {
} }
if (numberTable === false) { if (numberTable === false) {
return false; return [false, false];
} }
return numberTable.map((column) => { const table = PrayerCircleCalculator.inflateTable(memberIds, numberTable);
const idColumn: Record<string, string> = {}; const invertedTable = PrayerCircleCalculator.getInvertedChainTableFor(table);
Object.keys(column).forEach((index) => { return [table, invertedTable];
idColumn[memberIds[Number(index)]] = memberIds[column[Number(index)]];
});
return idColumn;
});
} }
static generateTable(numPrayers: number): Record<number, number>[] | false { static generateTable(numPrayers: number): Record<number, number>[] | false {
@ -4387,6 +4386,10 @@ export class PrayerCircleCalculator {
} }
private static generateChainTableFor(numPrayers: number) { private static generateChainTableFor(numPrayers: number) {
if (numPrayers < 2) {
return false;
}
const possiblePartnersBaseArray: number[] = []; const possiblePartnersBaseArray: number[] = [];
for (let i = 0; i < numPrayers; i++) { for (let i = 0; i < numPrayers; i++) {
possiblePartnersBaseArray.push(i); possiblePartnersBaseArray.push(i);
@ -4401,6 +4404,35 @@ export class PrayerCircleCalculator {
for (let i = 0; i < numPrayers - 1; i++) { for (let i = 0; i < numPrayers - 1; i++) {
table.push({}); table.push({});
} }
possiblePartnersBaseArray.forEach((member, index) => {
const otherMembers = possiblePartners[member];
for (let i = 0; i < numPrayers - 1; i++) {
table[i][member] = otherMembers[(index + i) % otherMembers.length];
}
});
return table; return table;
} }
static getInvertedChainTableFor(table: Record<string, string>[]) {
return table.map((column) => {
const invertedColumn: Record<string, string> = {};
Object.keys(column).forEach((id1) => {
invertedColumn[column[id1]] = id1;
});
return invertedColumn;
});
}
private static inflateTable(memberIds: string[], table: Column[]) {
return table.map((column) => {
const idColumn: Record<string, string> = {};
Object.keys(column).forEach((index) => {
idColumn[memberIds[Number(index)]] = memberIds[column[Number(index)]];
});
return idColumn;
});
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,7 @@ import { Checkbox, Switch } from 'react-bootstrap-mobile';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { useAppDispatch, useAppSelector } from '../Store/reduxHooks'; import { useAppDispatch, useAppSelector } from '../Store/reduxHooks';
import { setUsePartners, setUseWeekdays } from './prayerCircleSlice'; import { setUsePartners, setUseWeekdays } from './prayerCircleSlice';
import { setDesign } from '../Settings/settingsSlice';
export type PrayerCircleSettingsProps = {}; export type PrayerCircleSettingsProps = {};
@ -11,6 +12,7 @@ function PrayerCircleSettings({}: PrayerCircleSettingsProps) {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const useWeekdays = useAppSelector((store) => store.prayerCircle.useWeekdays ?? false); const useWeekdays = useAppSelector((store) => store.prayerCircle.useWeekdays ?? false);
const usePartners = useAppSelector((store) => store.prayerCircle.usePartners ?? true); const usePartners = useAppSelector((store) => store.prayerCircle.usePartners ?? true);
const design = useAppSelector((state) => state.settings.design);
// States // States
@ -19,6 +21,13 @@ function PrayerCircleSettings({}: PrayerCircleSettingsProps) {
// Callbacks // Callbacks
const onChangeUseWeekdays = useCallback(({ target: { checked } }) => dispatch(setUseWeekdays(checked)), [dispatch]); const onChangeUseWeekdays = useCallback(({ target: { checked } }) => dispatch(setUseWeekdays(checked)), [dispatch]);
const onChangeUsePartners = useCallback(({ target: { checked } }) => dispatch(setUsePartners(checked)), [dispatch]); const onChangeUsePartners = useCallback(({ target: { checked } }) => dispatch(setUsePartners(checked)), [dispatch]);
const toggleThemeCallback = useCallback(() => {
if (design === 'material') {
dispatch(setDesign('flat'));
} else {
dispatch(setDesign('material'));
}
}, [dispatch, design]);
// Effects // Effects
@ -33,6 +42,16 @@ function PrayerCircleSettings({}: PrayerCircleSettingsProps) {
</Switch> </Switch>
<br /> <br />
<Checkbox label="Benutze Wochentage" checked={useWeekdays} onChange={onChangeUseWeekdays} /> <Checkbox label="Benutze Wochentage" checked={useWeekdays} onChange={onChangeUseWeekdays} />
<br />
<Switch
id="switchTheme"
checked={design === 'flat'}
preLabel="android"
isDual={true}
onChange={toggleThemeCallback}
>
ios
</Switch>
</> </>
); );
} }

View File

@ -1,49 +0,0 @@
import * as React from 'react';
import { Sites, useTopBar } from 'cordova-sites';
import { FunctionComponent, useCallback } from 'react';
import { Button, Switch } from 'react-bootstrap-mobile';
import { useAppDispatch, useAppSelector } from '../Store/reduxHooks';
import { setDesign } from './settingsSlice';
type Props = {};
export const Settings: FunctionComponent<Props> = React.memo(({}) => {
// Variables
const design = useAppSelector((state) => state.settings.design);
const isActive = design === 'flat';
const dispatch = useAppDispatch();
// States
// Refs
// Callbacks
const toggleThemeCallback = useCallback(() => {
if (design === 'material') {
dispatch(setDesign('flat'));
} else {
dispatch(setDesign('material'));
}
}, [dispatch, design]);
// Effects
useTopBar({
title: 'Settings',
});
// Other
// Render Functions
return (
<>
<br />
<br />
<Switch id="switchTheme" checked={isActive} preLabel="android" isDual={true} onChange={toggleThemeCallback}>
ios
</Switch>
<Button onClick={toggleThemeCallback}>Change Theme</Button>
</>
);
});
Sites.addInitialization((app) => app.addDeepLink('/Settings', Settings));

View File

@ -1,46 +0,0 @@
import * as React from 'react';
import { Sites, useSites, useTopBar } from 'cordova-sites';
import { FunctionComponent } from 'react';
import { Settings } from '../Settings/Settings';
import { Input, Switch } from 'react-bootstrap-mobile';
type Props = {};
export const TaskList: FunctionComponent<Props> = React.memo(({}) => {
// Variables
const sites = useSites();
// States
// Refs
// Callbacks
// Effects
useTopBar({
title: 'TaskList',
rightButtons: [
{
title: 'Settings',
action: () => {
sites?.startSite(Settings);
},
},
],
});
// Other
// Render Functions
return (
<>
<br />
<br />
<Input label="test" placeholder="Your Text" />
<Switch id="switchTheme" isDual={false} preLabel="android" onChange={(e) => console.log(e.target.checked)}>
ios
</Switch>
</>
);
});
Sites.addInitialization((app) => app.addDeepLink('/TaskList', TaskList));

View File

@ -1,22 +0,0 @@
import { createSlice } from '@reduxjs/toolkit';
export const tasksSlice = createSlice({
name: 'tasks',
initialState: {
value: 0,
},
reducers: {
increment: (state) => {
state.value += 1;
},
decrement: (state) => {
state.value -= 1;
},
incrementByAmount: (state, action) => {
state.value += action.payload;
},
},
});
export const { increment, decrement, incrementByAmount } = tasksSlice.actions;
export default tasksSlice.reducer;