diff --git a/src/components/matches/MatchDetail.tsx b/src/components/matches/MatchDetail.tsx
index 2f49255..878b980 100644
--- a/src/components/matches/MatchDetail.tsx
+++ b/src/components/matches/MatchDetail.tsx
@@ -1,13 +1,6 @@
import { MatchVariant, MatchWithDetails } from "@boklisten/bl-model";
import { ArrowBack } from "@mui/icons-material";
-import {
- Alert,
- Button,
- Card,
- Container,
- Skeleton,
- Typography,
-} from "@mui/material";
+import { Alert, Button, Card, Container, Skeleton } from "@mui/material";
import React from "react";
import useSWR from "swr";
@@ -66,7 +59,6 @@ const MatchDetail = ({ matchId }: { matchId: string }) => {
>
}>Alle overleveringer
- Overlevering av bøker
{match._variant === MatchVariant.StandMatch && (
diff --git a/src/components/matches/MeetingInfo.tsx b/src/components/matches/MeetingInfo.tsx
index 7736b3a..13aedca 100644
--- a/src/components/matches/MeetingInfo.tsx
+++ b/src/components/matches/MeetingInfo.tsx
@@ -5,39 +5,39 @@ import { Box, Typography } from "@mui/material";
import React from "react";
import DynamicLink from "@/components/DynamicLink";
-import { formatDatetime } from "@/components/matches/matchesList/helper";
+import { FormattedDatetime } from "@/components/matches/matchesList/helper";
const MeetingInfo = ({ match }: { match: MatchWithDetails }) => {
const meetingTime = match.meetingInfo.date;
const meetingLocation = match.meetingInfo.location;
return (
-
-
-
-
- {meetingLocation}
-
-
+
{(meetingTime && (
- <>
-
- {formatDatetime(new Date(meetingTime))}
-
- >
+
)) || (
- <>
-
- Du kan møte opp når som helst i{" "}
-
- skolens åpningstider
-
-
- >
+
+ Du kan møte opp når som helst i{" "}
+
+ skolens åpningstider
+
+
)}
+
+
+ {meetingLocation}
+
);
};
diff --git a/src/components/matches/OtherPersonContact.tsx b/src/components/matches/OtherPersonContact.tsx
index 635b0d7..207a0a8 100644
--- a/src/components/matches/OtherPersonContact.tsx
+++ b/src/components/matches/OtherPersonContact.tsx
@@ -27,15 +27,37 @@ const OtherPersonContact = ({
sx={{ display: "flex", alignItems: "center", justifyContent: "left" }}
>
-
- {otherPerson.name}
-
-
- {otherPerson.phone}
+
+ {otherPerson.name},{" "}
+
+ {formatPhoneNumber(otherPerson.phone)}
-
+
);
};
+function formatPhoneNumber(number: string): string {
+ if (/\d{8}/.exec(number) !== null) {
+ return (
+ number.slice(0, 3) + " " + number.slice(3, 5) + " " + number.slice(5, 8)
+ );
+ }
+ if (/\d{10}/.exec(number) !== null) {
+ return (
+ number.slice(2) +
+ " " +
+ number.slice(2, 5) +
+ " " +
+ number.slice(5, 7) +
+ " " +
+ number.slice(7, 10)
+ );
+ }
+ return number;
+}
+
export default OtherPersonContact;
diff --git a/src/components/matches/StandMatchDetail.tsx b/src/components/matches/StandMatchDetail.tsx
index c5929bc..bc12c9f 100644
--- a/src/components/matches/StandMatchDetail.tsx
+++ b/src/components/matches/StandMatchDetail.tsx
@@ -1,4 +1,4 @@
-import { Alert } from "@mui/material";
+import { Alert, Typography } from "@mui/material";
import React from "react";
import {
@@ -7,6 +7,7 @@ import {
ItemStatus,
MatchHeader,
} from "@/components/matches/matches-helper";
+import { StandMatchTitle } from "@/components/matches/matchesList/helper";
import ProgressBar from "@/components/matches/matchesList/ProgressBar";
import MatchItemTable from "@/components/matches/MatchItemTable";
import MeetingInfo from "@/components/matches/MeetingInfo";
@@ -49,6 +50,10 @@ const StandMatchDetail = ({
return (
<>
+
+
+
+
{isFulfilled && (
Du har mottatt og levert alle bøkene for denne overleveringen.
@@ -99,7 +104,7 @@ const StandMatchDetail = ({
>
)}
- Du skal på stand ved
+ Du skal på stand:
Kontaktinformasjon
diff --git a/src/components/matches/UserMatchDetail.tsx b/src/components/matches/UserMatchDetail.tsx
index 3f7834e..c6a4e0b 100644
--- a/src/components/matches/UserMatchDetail.tsx
+++ b/src/components/matches/UserMatchDetail.tsx
@@ -7,6 +7,7 @@ import {
ItemStatus,
MatchHeader,
} from "@/components/matches/matches-helper";
+import { UserMatchTitle } from "@/components/matches/matchesList/helper";
import ProgressBar from "@/components/matches/matchesList/ProgressBar";
import MatchItemTable from "@/components/matches/MatchItemTable";
import MeetingInfo from "@/components/matches/MeetingInfo";
@@ -48,6 +49,10 @@ const UserMatchDetail = ({
return (
<>
+
+
+
+
{isFulfilled && (
Du har {isSender ? "levert" : "mottatt"} alle bøkene for denne
@@ -83,8 +88,8 @@ const UserMatchDetail = ({
Du skal møte
-
+
{!isSender && !isFulfilled && (
<>
diff --git a/src/components/matches/matchesList/MatchListItemBox.tsx b/src/components/matches/matchesList/MatchListItemBox.tsx
index 6ffdd18..487c3f3 100644
--- a/src/components/matches/matchesList/MatchListItemBox.tsx
+++ b/src/components/matches/matchesList/MatchListItemBox.tsx
@@ -1,8 +1,14 @@
-import { Button, Card, CardActions, CardContent } from "@mui/material";
+import {
+ Button,
+ Card,
+ CardActionArea,
+ CardActions,
+ CardContent,
+} from "@mui/material";
+import { green, grey } from "@mui/material/colors";
import React, { PropsWithChildren } from "react";
import DynamicLink from "@/components/DynamicLink";
-
const MatchListItemBox: React.FC<
PropsWithChildren<{ finished: boolean; matchId: string }>
> = ({ finished, matchId, children }) => {
@@ -10,17 +16,23 @@ const MatchListItemBox: React.FC<
- {children}
-
-
-
+
+ {children}
+
+
+
+
);
};
diff --git a/src/components/matches/matchesList/MatchListItemGroups.tsx b/src/components/matches/matchesList/MatchListItemGroups.tsx
index 6ec4602..65c662e 100644
--- a/src/components/matches/matchesList/MatchListItemGroups.tsx
+++ b/src/components/matches/matchesList/MatchListItemGroups.tsx
@@ -2,50 +2,33 @@ import { MatchVariant, MatchWithDetails } from "@boklisten/bl-model";
import { Typography } from "@mui/material";
import React from "react";
-import {
- formatDatetime,
- sectionStyle,
- getSortedMatchGroups,
-} from "@/components/matches/matchesList/helper";
+import { sectionStyle } from "@/components/matches/matchesList/helper";
import StandMatchListItem from "@/components/matches/matchesList/StandMatchListItem";
import UserMatchListItem from "@/components/matches/matchesList/UserMatchListItem";
-import { GroupedMatches } from "@/utils/types";
export const MatchListItemGroups: React.FC<{
- groups: GroupedMatches;
+ matches: MatchWithDetails[];
userId: string;
- heading: string;
-}> = ({ groups, userId, heading }) => {
+ heading?: string;
+}> = ({ matches, userId, heading }) => {
return (
- {heading}
- {getSortedMatchGroups(groups).map((key) => {
- const { time, location } = groups.keyToData.get(key)!;
- return (
-
-
- {time ? formatDatetime(new Date(time)) : ""} {location}
-
- {groups.matchesByKey
- .get(key)!
- .map((match) =>
- match._variant === MatchVariant.StandMatch ? (
-
- ) : (
-
- ),
- )}
-
- );
- })}
+ {heading && {heading}}
+ {matches.map((match) =>
+ match._variant === MatchVariant.StandMatch ? (
+
+ ) : (
+
+ ),
+ )}
);
};
diff --git a/src/components/matches/matchesList/MatchesList.tsx b/src/components/matches/matchesList/MatchesList.tsx
index 1cafa29..7563add 100644
--- a/src/components/matches/matchesList/MatchesList.tsx
+++ b/src/components/matches/matchesList/MatchesList.tsx
@@ -1,4 +1,4 @@
-import { MatchVariant, MatchWithDetails } from "@boklisten/bl-model";
+import { MatchWithDetails } from "@boklisten/bl-model";
import { Alert, Skeleton } from "@mui/material";
import React from "react";
import useSWR from "swr";
@@ -9,11 +9,9 @@ import {
isMatchFulfilled,
isUserSenderInMatch,
} from "@/components/matches/matches-helper";
-import { groupMatchesByTimeAndLocation } from "@/components/matches/matchesList/helper";
import { MatchListItemGroups } from "@/components/matches/matchesList/MatchListItemGroups";
import ProgressBar from "@/components/matches/matchesList/ProgressBar";
import BL_CONFIG from "@/utils/bl-config";
-import { StandMatchWithDetails, UserMatchWithDetails } from "@/utils/types";
export const MatchesList: React.FC = () => {
const { data: accessToken, error: tokenError } = useSWR("userId", () =>
@@ -22,9 +20,6 @@ export const MatchesList: React.FC = () => {
const userId = accessToken?.details;
const { data: matches, error: matchesError } = useSWR(
`${BL_CONFIG.collection.match}/me`,
- // The following line errors in WebStorm for some reason, but it's allowed.
- // WebStorm accepts it wrapped in parentheses, but then prettier doesn't, so
- // just ignore it.
apiFetcher,
{ refreshInterval: 5000 },
);
@@ -36,25 +31,25 @@ export const MatchesList: React.FC = () => {
if (matches === undefined) {
return ;
}
+ const sortedMatches = matches.sort((a, b) => {
+ if (!a.meetingInfo.date) {
+ return b.meetingInfo.date ? 1 : 0;
+ } else if (!b.meetingInfo.date) {
+ return -1;
+ }
- const standMatches = matches
- .filter((match) => match._variant === MatchVariant.StandMatch)
- .map((standMatch) => standMatch as StandMatchWithDetails)
- .sort((a, b) =>
- isMatchFulfilled(a, false) ? 1 : isMatchFulfilled(b, false) ? -1 : 0,
- );
- const userMatches = matches
- .filter((match) => match._variant === MatchVariant.UserMatch)
- .map((userMatch) => userMatch as UserMatchWithDetails)
- .sort((a, b) =>
- isMatchFulfilled(a, isUserSenderInMatch(a, userId))
- ? 1
- : isMatchFulfilled(b, isUserSenderInMatch(b, userId))
- ? -1
- : 0,
- );
- const standMatchesByTime = groupMatchesByTimeAndLocation(standMatches);
- const userMatchesByTime = groupMatchesByTimeAndLocation(userMatches);
+ if (a.meetingInfo.date > b.meetingInfo.date) return 1;
+ if (a.meetingInfo.date < b.meetingInfo.date) return -1;
+
+ return 0;
+ });
+
+ const unfulfilledMatches = sortedMatches.filter(
+ (match) => !isMatchFulfilled(match, isUserSenderInMatch(match, userId)),
+ );
+ const fulfilledMatches = sortedMatches.filter((match) =>
+ isMatchFulfilled(match, isUserSenderInMatch(match, userId)),
+ );
if (matches.length === 0) {
return Du har ingen overleveringer :);
@@ -75,19 +70,15 @@ export const MatchesList: React.FC = () => {
}
/>
- {userMatches.length > 0 && (
-
+ {unfulfilledMatches.length > 0 && (
+
)}
- {standMatches.length > 0 && (
+ {fulfilledMatches.length > 0 && (
)}
>
diff --git a/src/components/matches/matchesList/StandMatchListItem.tsx b/src/components/matches/matchesList/StandMatchListItem.tsx
index dbd0ad4..d2e0007 100644
--- a/src/components/matches/matchesList/StandMatchListItem.tsx
+++ b/src/components/matches/matchesList/StandMatchListItem.tsx
@@ -1,4 +1,4 @@
-import { Box } from "@mui/material";
+import { Box, Typography } from "@mui/material";
import React from "react";
import {
@@ -6,9 +6,13 @@ import {
isMatchBegun,
isMatchFulfilled,
} from "@/components/matches/matches-helper";
-import { formatActionsString } from "@/components/matches/matchesList/helper";
+import {
+ formatActionsString,
+ StandMatchTitle,
+} from "@/components/matches/matchesList/helper";
import MatchListItemBox from "@/components/matches/matchesList/MatchListItemBox";
import ProgressBar from "@/components/matches/matchesList/ProgressBar";
+import MeetingInfo from "@/components/matches/MeetingInfo";
import { StandMatchWithDetails } from "@/utils/types";
const StandMatchListItem: React.FC<{
@@ -25,6 +29,9 @@ const StandMatchListItem: React.FC<{
const isFulfilled = isMatchFulfilled(match, false);
return (
+
+
+
{isBegun && (
<>
{hasHandoffItems && (
@@ -66,6 +73,7 @@ const StandMatchListItem: React.FC<{
>
)}
+ {!isFulfilled && }
);
};
diff --git a/src/components/matches/matchesList/UserMatchListItem.tsx b/src/components/matches/matchesList/UserMatchListItem.tsx
index 7fcc713..3d18374 100644
--- a/src/components/matches/matchesList/UserMatchListItem.tsx
+++ b/src/components/matches/matchesList/UserMatchListItem.tsx
@@ -1,4 +1,3 @@
-import { KeyboardDoubleArrowRight } from "@mui/icons-material";
import { Box, Typography } from "@mui/material";
import React from "react";
@@ -8,13 +7,15 @@ import {
isMatchFulfilled,
isUserSenderInMatch,
} from "@/components/matches/matches-helper";
-import { formatActionsString } from "@/components/matches/matchesList/helper";
+import {
+ formatActionsString,
+ UserMatchTitle,
+} from "@/components/matches/matchesList/helper";
import MatchListItemBox from "@/components/matches/matchesList/MatchListItemBox";
import ProgressBar from "@/components/matches/matchesList/ProgressBar";
+import MeetingInfo from "@/components/matches/MeetingInfo";
import { UserMatchWithDetails } from "@/utils/types";
-const me = Meg;
-
const UserMatchListItem: React.FC<{
match: UserMatchWithDetails;
currentUserId: string;
@@ -27,26 +28,11 @@ const UserMatchListItem: React.FC<{
match,
isSender,
);
- const HeaderLevel = "h4";
return (
- {isSender ? (
-
- {me}{" "}
- {" "}
- {match.receiverDetails.name}
-
- ) : (
-
- {match.senderDetails.name}{" "}
- {" "}
- {me}
-
- )}
+
+
+
{isBegun && (
<>
@@ -71,6 +57,7 @@ const UserMatchListItem: React.FC<{
>
)}
+ {!isFulfilled && }
);
};
diff --git a/src/components/matches/matchesList/helper.tsx b/src/components/matches/matchesList/helper.tsx
index 5fa1b5b..9449737 100644
--- a/src/components/matches/matchesList/helper.tsx
+++ b/src/components/matches/matchesList/helper.tsx
@@ -1,12 +1,17 @@
-import { MatchWithDetails } from "@boklisten/bl-model";
+import { KeyboardDoubleArrowRight, SwapHoriz } from "@mui/icons-material";
+import { SxProps, Typography } from "@mui/material";
+import { Box } from "@mui/system";
import { Properties } from "csstype";
+import React from "react";
-import { GroupedMatches } from "@/utils/types";
+import theme from "@/utils/theme";
+import { StandMatchWithDetails, UserMatchWithDetails } from "@/utils/types";
export const sectionStyle: Properties = {
display: "flex",
flexDirection: "column",
gap: "1em",
+ marginTop: "1rem",
};
export function formatActionsString(handoffItems: number, pickupItems: number) {
@@ -43,65 +48,94 @@ export function formatActionsString(handoffItems: number, pickupItems: number) {
return stringBuilder.join("");
}
-/**
- * Groups array of matches location.
- *
- * If the input-array is sorted by time, then the output will be as well
- * (assuming for-of or other insertion-order iteration of keys).
- *
- * @param matches the matches to group
- */
-export function groupMatchesByTimeAndLocation(
- matches: T[],
-): GroupedMatches {
- const keyToData: Map =
- new Map();
- const matchesByKey: Map = new Map();
- for (const match of matches) {
- const date = match.meetingInfo.date
- ? new Date(match.meetingInfo.date)
- : null;
- const key = (date?.getTime() ?? null) + match.meetingInfo.location;
- const items = matchesByKey.get(key) ?? [];
- keyToData.set(key, {
- time: date?.getTime() ?? null,
- location: match.meetingInfo.location,
- });
- matchesByKey.set(key, items);
- items.push(match);
- }
- return { matchesByKey, keyToData };
-}
-
-/**
- * Sort groups by time ascending.
- *
- * @param groups the groups to sort
- * @returns array of keys of groups
- */
-export function getSortedMatchGroups(
- groups: GroupedMatches,
-): string[] {
- const keys = [...groups.keyToData.keys()];
- keys.sort((a, b) => {
- const timeA = groups.keyToData.get(a)!.time;
- const timeB = groups.keyToData.get(b)!.time;
- if (!timeA) {
- return 1;
- }
- if (!timeB) {
- return -1;
- }
- return new Date(timeA) >= new Date(timeB) ? 1 : -1;
+export const FormattedDatetime = ({ date }: { date: Date }) => {
+ const dateString = date.toLocaleDateString("no", {
+ timeZone: "Europe/Oslo",
+ dateStyle: "long",
});
- return keys;
-}
-
-export function formatDatetime(date: Date): string {
- const dateString = date.toLocaleDateString("no", { timeZone: "Europe/Oslo" });
const timeString = date.toLocaleTimeString("no", {
timeZone: "Europe/Oslo",
timeStyle: "short",
});
- return `${dateString} ${timeString}`;
+ return (
+ <>
+ {timeString}
+ , {dateString}
+ >
+ );
+};
+
+const me = Meg;
+
+interface UserMatchTitleProps {
+ match: UserMatchWithDetails;
+ isSender: boolean;
}
+
+export const UserMatchTitle = ({ match, isSender }: UserMatchTitleProps) => {
+ const arrowSize: string = "1.18em";
+ return (
+ <>
+ {isSender ? (
+ <>
+ {me}{" "}
+ {" "}
+
+ {match.receiverDetails.name}
+
+ >
+ ) : (
+ <>
+
+ {match.senderDetails.name}
+ {" "}
+ {" "}
+ {me}
+ >
+ )}
+ >
+ );
+};
+
+interface StandMatchTitleProps {
+ match: StandMatchWithDetails;
+}
+
+export const StandMatchTitle = ({ match }: StandMatchTitleProps) => {
+ const hasHandoffItems = match.expectedHandoffItems.length > 0;
+ const hasPickupItems = match.expectedPickupItems.length > 0;
+
+ const stand = (
+
+ Stand
+
+ );
+
+ const isMeFirst = hasPickupItems ? hasHandoffItems : true;
+
+ const iconStyle: SxProps = {
+ verticalAlign: "text-bottom",
+ fontSize: "1.18em",
+ };
+
+ const left = isMeFirst ? me : stand;
+ const right = isMeFirst ? stand : me;
+ const arrow = hasHandoffItems ? (
+ hasPickupItems ? (
+
+ ) : (
+
+ )
+ ) : (
+
+ );
+ return (
+ <>
+ {left} {arrow} {right}
+ >
+ );
+};
diff --git a/src/utils/typographyVariants.ts b/src/utils/typographyVariants.ts
index d247e0f..a25c4f7 100644
--- a/src/utils/typographyVariants.ts
+++ b/src/utils/typographyVariants.ts
@@ -4,19 +4,13 @@
*/
import React from "react";
-// @ts-expect-error used for module JSdoc
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
-import theme from "@/utils/theme";
-
declare module "@mui/material/styles" {
- // eslint-disable-next-line no-unused-vars
interface TypographyVariants {
cardHeader: React.CSSProperties;
title: React.CSSProperties;
}
// allow configuration using `createTheme`
- // eslint-disable-next-line no-unused-vars
interface TypographyVariantsOptions {
cardHeader?: React.CSSProperties;
title?: React.CSSProperties;
@@ -25,7 +19,6 @@ declare module "@mui/material/styles" {
// Update the Typography's variant prop options
declare module "@mui/material/Typography" {
- // eslint-disable-next-line no-unused-vars
interface TypographyPropsVariantOverrides {
cardHeader: true;
title: true;
diff --git a/tsconfig.json b/tsconfig.json
index a5cbd61..a2dc08c 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -6,8 +6,6 @@
"checkJs": true,
"skipLibCheck": true,
"strict": true,
- "noUnusedLocals": true,
- "noUnusedParameters": true,
"exactOptionalPropertyTypes": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,