From 857ea8f196bc1eaaf3dfa143371ed4e78eecc62a Mon Sep 17 00:00:00 2001
From: sverben <59171289+sverben@users.noreply.github.com>
Date: Sat, 25 May 2024 15:02:48 +0200
Subject: [PATCH 1/2] feat: register members
---
package.json | 1 +
src/components/register/listing.tsx | 16 +--
src/components/register/presence.tsx | 59 ++++++++++
src/screens/feed/feed.tsx | 7 +-
src/screens/feed/slot.tsx | 157 ++++++++++++++++++++-------
src/stores/register.ts | 19 +++-
yarn.lock | 5 +
7 files changed, 215 insertions(+), 49 deletions(-)
create mode 100644 src/components/register/presence.tsx
diff --git a/package.json b/package.json
index 8efe8a4..9b73799 100644
--- a/package.json
+++ b/package.json
@@ -35,6 +35,7 @@
"react-native-maps": "1.15.3",
"react-native-pager-view": "6.3.1",
"react-native-paper": "^5.12.3",
+ "react-native-paper-select": "^1.1.1",
"react-native-safe-area-context": "4.10.1",
"react-native-screens": "~3.31.1",
"react-native-vector-icons": "^10.0.3",
diff --git a/src/components/register/listing.tsx b/src/components/register/listing.tsx
index cdafb70..9ff712d 100644
--- a/src/components/register/listing.tsx
+++ b/src/components/register/listing.tsx
@@ -1,7 +1,7 @@
import { useContext, useEffect } from "react";
import AuthContext, { Authed } from "../../auth";
import { useAtom } from "jotai";
-import { getSlots, Slot, slotsAtom } from "../../stores/register";
+import { getSlots, membersAtom, Slot, slotsAtom } from "../../stores/register";
import {
ActivityIndicator,
Avatar,
@@ -39,16 +39,18 @@ function SlotListing({ slot, index }: { slot: Slot; index: number }) {
export default function Listing() {
const authState = useContext(AuthContext);
const [slots, setSlots] = useAtom(slotsAtom);
+ const [_members, setMembers] = useAtom(membersAtom);
useEffect(() => {
async function fetchDays() {
- setSlots(
- await getSlots(
- authState.authenticated === Authed.AUTHENTICATED
- ? await authState.token
- : null,
- ),
+ const { slots, members } = await getSlots(
+ authState.authenticated === Authed.AUTHENTICATED
+ ? await authState.token
+ : null,
);
+
+ setSlots(slots);
+ setMembers(members || []);
}
fetchDays().then();
diff --git a/src/components/register/presence.tsx b/src/components/register/presence.tsx
new file mode 100644
index 0000000..ee8505f
--- /dev/null
+++ b/src/components/register/presence.tsx
@@ -0,0 +1,59 @@
+import {
+ getSlots,
+ Presence as PresenceType,
+ Slot,
+ slotsAtom,
+} from "../../stores/register";
+import { ActivityIndicator, Checkbox, Switch, Text } from "react-native-paper";
+import { StyleSheet, TouchableOpacity } from "react-native";
+import { useContext, useState } from "react";
+import AuthContext, { Authed } from "../../auth";
+import { useAtom } from "jotai";
+import { Platform } from "react-native";
+
+export default function Presence({
+ presence,
+ slot,
+}: {
+ presence: PresenceType;
+ slot: Slot;
+}) {
+ const [slots, setSlots] = useAtom(slotsAtom);
+ const [seen, setSeen] = useState(presence.seen);
+ const authState = useContext(AuthContext);
+
+ async function markSeen() {
+ if (authState.authenticated !== Authed.AUTHENTICATED) return;
+ if (!slots) return;
+
+ presence.seen = !presence.seen;
+ setSeen(presence.seen);
+ setSlots(slots);
+
+ const token = await authState.token;
+ await fetch(
+ `https://aanmelden.djoamersfoort.nl/api/v1/seen/${presence.id}/${presence.seen ? "true" : "false"}`,
+ {
+ headers: {
+ authorization: `Bearer ${token}`,
+ },
+ },
+ );
+ }
+
+ return (
+
+
+ {presence.name}
+
+ );
+}
+
+const styles = StyleSheet.create({
+ presence: {
+ display: "flex",
+ flexDirection: "row",
+ alignItems: "center",
+ gap: 10,
+ },
+});
diff --git a/src/screens/feed/feed.tsx b/src/screens/feed/feed.tsx
index d7acd34..9f4fddc 100644
--- a/src/screens/feed/feed.tsx
+++ b/src/screens/feed/feed.tsx
@@ -10,7 +10,7 @@ import {
getRSSFeed,
sortFeeds,
} from "../../stores/feed";
-import { getSlots, slotsAtom } from "../../stores/register";
+import { getSlots, slotsAtom, membersAtom } from "../../stores/register";
import AuthContext, { Authed } from "../../auth";
import { NativeStackNavigationProp } from "react-native-screens/native-stack";
import { StackParamList } from "../../../App";
@@ -25,6 +25,7 @@ export default function FeedScreen() {
const authState = useContext(AuthContext);
const [_feed, setFeed] = useAtom(feedAtom);
const [_slots, setSlots] = useAtom(slotsAtom);
+ const [_members, setMembers] = useAtom(membersAtom);
async function refresh() {
setRefreshing(true);
@@ -35,8 +36,10 @@ export default function FeedScreen() {
await Promise.all([
new Promise(async (resolve) => {
setSlots(null);
- const slots = await getSlots(token);
+ const { slots, members } = await getSlots(token);
setSlots(slots);
+ setMembers(members || []);
+
resolve();
}),
new Promise(async (resolve) => {
diff --git a/src/screens/feed/slot.tsx b/src/screens/feed/slot.tsx
index bbd3dcf..37ba289 100644
--- a/src/screens/feed/slot.tsx
+++ b/src/screens/feed/slot.tsx
@@ -1,11 +1,26 @@
import { StackScreenProps } from "@react-navigation/stack";
-import { Alert, StyleSheet, View } from "react-native";
-import { Button, Card, Chip, Text } from "react-native-paper";
+import {
+ Alert,
+ ScrollView,
+ StyleSheet,
+ TouchableOpacity,
+ View,
+} from "react-native";
+import {
+ Button,
+ Card,
+ Checkbox,
+ Chip,
+ Text,
+ useTheme,
+} from "react-native-paper";
import { useContext, useEffect, useState } from "react";
-import { getSlots, Slot, slotsAtom } from "../../stores/register";
+import { getSlots, membersAtom, Slot, slotsAtom } from "../../stores/register";
import { useAtom } from "jotai";
import { StackParamList } from "../../../App";
import AuthContext, { Authed } from "../../auth";
+import Presence from "../../components/register/presence";
+import { PaperSelect } from "react-native-paper-select";
type Props = StackScreenProps;
@@ -15,9 +30,27 @@ export default function SlotScreen({ route, navigation }: Props) {
const [slot, setSlot] = useState(slots[route.params.slot]);
const [loading, setLoading] = useState(false);
+ const [members] = useAtom(membersAtom);
+ const theme = useTheme();
const authState = useContext(AuthContext);
+ async function registerManual(user: string) {
+ if (authState.authenticated !== Authed.AUTHENTICATED) return;
+
+ const token = await authState.token;
+ await fetch(
+ `https://aanmelden.djoamersfoort.nl/api/v1/register_manual/${slot.name}/${slot.pod}/${user}`,
+ {
+ headers: {
+ authorization: `Bearer ${token}`,
+ },
+ },
+ );
+
+ setSlots((await getSlots(token)).slots);
+ }
+
async function register() {
setLoading(true);
const token =
@@ -49,7 +82,7 @@ export default function SlotScreen({ route, navigation }: Props) {
slot.is_registered = !slot.is_registered;
}
- setSlots(await getSlots(token));
+ setSlots((await getSlots(token)).slots);
setLoading(false);
}
@@ -61,39 +94,83 @@ export default function SlotScreen({ route, navigation }: Props) {
return (
-
- {slot.announcement && (
- <>
- Aankondiging
-
-
- {slot.announcement}
-
-
- >
- )}
- Beschikbaarheid
-
-
-
- Er zijn {slot.available}/{slot.available + slot.taken} plekken
- beschikbaar.
-
-
-
-
- Begeleiders
-
-
- {slot.tutors.length === 0 && (
- Er zijn nog geen begeleiders aangemeld
- )}
- {slot.tutors.map((tutor) => (
- {tutor}
- ))}
-
-
-
+
+
+ {slot.announcement && (
+ <>
+ Aankondiging
+
+
+ {slot.announcement}
+
+
+ >
+ )}
+ Beschikbaarheid
+
+
+
+ Er zijn {slot.available}/{slot.available + slot.taken} plekken
+ beschikbaar.
+
+
+
+
+ Begeleiders
+
+
+ {slot.tutors.length === 0 && (
+ Er zijn nog geen begeleiders aangemeld
+ )}
+ {slot.tutors.map((tutor) => (
+ {tutor}
+ ))}
+
+
+
+ {slot.presence && (
+ <>
+ Leden
+
+
+ a.name < b.name ? -1 : 1) .map(({ id, name }) => ({
+ _id: id.toString(),
+ value: name,
+ }))}
+ selectedArrayList={[]}
+ multiEnable={false}
+ value={""}
+ onSelection={async (selection) => {
+ if (!selection.selectedList[0]) return;
+ await registerManual(selection.selectedList[0]._id);
+ }}
+ theme={theme}
+ textInputStyle={{
+ backgroundColor: theme.colors.elevation.level5,
+ color: theme.colors.onPrimaryContainer,
+ }}
+ searchStyle={{
+ backgroundColor: theme.colors.elevation.level5,
+ }}
+ textColor={theme.colors.onPrimary}
+ />
+
+ {slot.presence.map((presence) => (
+
+ ))}
+
+
+
+ >
+ )}
+
+