Skip to content

Commit

Permalink
Merge pull request #136 from eurofurence/feature/dealer-keywords
Browse files Browse the repository at this point in the history
feat: dealer keywords and home refactoring
  • Loading branch information
Requinard authored Aug 24, 2024
2 parents 4a4e8e5 + e379e17 commit 746dff7
Show file tree
Hide file tree
Showing 16 changed files with 225 additions and 81 deletions.
46 changes: 38 additions & 8 deletions src/components/dealers/DealerContent.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as Linking from "expo-linking";
import { TFunction } from "i18next";
import moment from "moment";
import React, { FC, useCallback, useMemo } from "react";
import { useTranslation } from "react-i18next";
Expand All @@ -23,6 +24,41 @@ import { Button } from "../generic/containers/Button";
import { ImageExButton } from "../generic/containers/ImageButton";
import { LinkItem } from "../maps/LinkItem";

const DealerCategories = ({ t, dealer }: { t: TFunction; dealer: DealerDetails }) => {
// Nothing to display for no categories.
if (!dealer.Categories?.length) return null;

return (
<>
<Label type="caption">{t("categories")}</Label>
<View style={dealerCategoriesStyles.container}>
{dealer.Categories.map((category: string) => {
const keywords = dealer.Keywords?.[category];
if (keywords?.length)
return (
<Label key={category} mt={5}>
<Label type="strong">{category}: </Label>
{keywords.join(", ")}
</Label>
);
else
return (
<Label key={category} type="strong">
{category}
</Label>
);
})}
</View>
</>
);
};

const dealerCategoriesStyles = StyleSheet.create({
container: {
marginBottom: 20,
},
});

/**
* Props to the content.
*/
Expand Down Expand Up @@ -133,14 +169,8 @@ export const DealerContent: FC<DealerContentProps> = ({ dealer, parentPad = 0, u
</>
)}

{!dealer.Categories?.length ? null : (
<>
<Label type="caption">{t("categories")}</Label>
<Label type="h3" mb={20}>
{dealer.Categories?.join(", ")}
</Label>
</>
)}
<DealerCategories t={t} dealer={dealer} />

{dealer.Links &&
dealer.Links.map((it) => (
<View style={styles.button} key={it.Name}>
Expand Down
5 changes: 3 additions & 2 deletions src/components/dealers/DealersList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,17 @@ export type DealersListProps = {
dealers: DealerDetailsInstance[];
empty?: ReactElement;
trailer?: ReactElement;
padEnd?: boolean;
};

export const DealersList: FC<DealersListProps> = ({ navigation, leader, dealers, empty, trailer }) => {
export const DealersList: FC<DealersListProps> = ({ navigation, leader, dealers, empty, trailer, padEnd = true }) => {
const theme = useThemeName();
const synchronizer = useSynchronizer();
return (
<FlashList
refreshing={synchronizer.isSynchronizing}
onRefresh={synchronizer.synchronize}
contentContainerStyle={styles.container}
contentContainerStyle={padEnd ? styles.container : undefined}
scrollEnabled={true}
ListHeaderComponent={leader}
ListFooterComponent={trailer}
Expand Down
5 changes: 3 additions & 2 deletions src/components/dealers/DealersSectionedList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@ export type DealersSectionedListProps = {
empty?: ReactElement;
trailer?: ReactElement;
sticky?: boolean;
padEnd?: boolean;
};

export const DealersSectionedList: FC<DealersSectionedListProps> = ({ navigation, leader, dealersGroups, empty, trailer, sticky = true }) => {
export const DealersSectionedList: FC<DealersSectionedListProps> = ({ navigation, leader, dealersGroups, empty, trailer, sticky = true, padEnd = true }) => {
const theme = useThemeName();
const synchronizer = useSynchronizer();
const stickyIndices = useMemo(() => (sticky ? findIndices(dealersGroups, (item) => !("details" in item)) : undefined), [dealersGroups, sticky]);
Expand All @@ -39,7 +40,7 @@ export const DealersSectionedList: FC<DealersSectionedListProps> = ({ navigation
<FlashList
refreshing={synchronizer.isSynchronizing}
onRefresh={synchronizer.synchronize}
contentContainerStyle={styles.container}
contentContainerStyle={padEnd ? styles.container : undefined}
scrollEnabled={true}
stickyHeaderIndices={stickyIndices}
ListHeaderComponent={leader}
Expand Down
5 changes: 3 additions & 2 deletions src/components/events/EventsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,17 @@ export type EventsListProps = {
empty?: ReactElement;
trailer?: ReactElement;
cardType?: "duration" | "time";
padEnd?: boolean;
};

export const EventsList: FC<EventsListProps> = ({ navigation, leader, events, select, empty, trailer, cardType = "duration" }) => {
export const EventsList: FC<EventsListProps> = ({ navigation, leader, events, select, empty, trailer, cardType = "duration", padEnd = true }) => {
const theme = useThemeName();
const synchronizer = useSynchronizer();
return (
<FlashList
refreshing={synchronizer.isSynchronizing}
onRefresh={synchronizer.synchronize}
contentContainerStyle={styles.container}
contentContainerStyle={padEnd ? styles.container : undefined}
scrollEnabled={true}
ListHeaderComponent={leader}
ListFooterComponent={trailer}
Expand Down
15 changes: 13 additions & 2 deletions src/components/events/EventsSectionedList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,20 @@ export type EventsSectionedListProps = {
trailer?: ReactElement;
cardType?: "duration" | "time";
sticky?: boolean;
padEnd?: boolean;
};

export const EventsSectionedList: FC<EventsSectionedListProps> = ({ navigation, leader, eventsGroups, select, empty, trailer, cardType = "duration", sticky = true }) => {
export const EventsSectionedList: FC<EventsSectionedListProps> = ({
navigation,
leader,
eventsGroups,
select,
empty,
trailer,
cardType = "duration",
sticky = true,
padEnd = true,
}) => {
const theme = useThemeName();
const synchronizer = useSynchronizer();
const stickyIndices = useMemo(() => (sticky ? findIndices(eventsGroups, (item) => !("details" in item)) : undefined), [eventsGroups, sticky]);
Expand All @@ -42,7 +53,7 @@ export const EventsSectionedList: FC<EventsSectionedListProps> = ({ navigation,
<FlashList
refreshing={synchronizer.isSynchronizing}
onRefresh={synchronizer.synchronize}
contentContainerStyle={styles.container}
contentContainerStyle={padEnd ? styles.container : undefined}
scrollEnabled={true}
stickyHeaderIndices={stickyIndices}
ListHeaderComponent={leader}
Expand Down
2 changes: 1 addition & 1 deletion src/components/events/TodayScheduleList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const TodayScheduleList: FC<TodayScheduleListProps> = ({ now }) => {
[favorites, now],
);

if (favorites.length === 0) {
if (events.length === 0) {
return null;
}

Expand Down
5 changes: 5 additions & 0 deletions src/components/generic/atoms/Label.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ const types = StyleSheet.create({
lineHeight: 24,
fontWeight: "100",
},
xl: {
fontSize: 44,
lineHeight: 48,
fontWeight: "500",
},
h1: {
fontSize: 30,
lineHeight: 34,
Expand Down
58 changes: 37 additions & 21 deletions src/components/home/CountdownHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { TFunction } from "i18next";
import { chain } from "lodash";
import { Moment } from "moment";
import moment from "moment/moment";
import { FC } from "react";
import React, { FC } from "react";
import { useTranslation } from "react-i18next";
import { StyleProp, StyleSheet, useWindowDimensions, View, ViewStyle } from "react-native";

Expand All @@ -15,7 +15,9 @@ import { EventDayRecord } from "../../store/eurofurence/types";
import { assetSource } from "../../util/assets";
import { Image } from "../generic/atoms/Image";
import { ImageBackground } from "../generic/atoms/ImageBackground";
import { Section } from "../generic/atoms/Section";
import { Label } from "../generic/atoms/Label";
import { Col } from "../generic/containers/Col";
import { Row } from "../generic/containers/Row";

export type CountdownHeaderProps = {
style?: StyleProp<ViewStyle>;
Expand Down Expand Up @@ -56,49 +58,63 @@ export const CountdownHeader: FC<CountdownHeaderProps> = ({ style }) => {
const { width } = useWindowDimensions();

const subtitle = useCountdownTitle(t, now);

return (
<View style={[styles.container, style]}>
<ImageBackground
key="banner"
style={styles.background}
style={StyleSheet.absoluteFill}
source={assetSource(width < bannerBreakpoint ? "banner_narrow" : "banner_wide")}
contentFit="cover"
priority="high"
/>
<Section
style={styles.section}
title={conId}
icon="alarm"
subtitle={subtitle}
titleColor="white"
subtitleColor="white"
titleVariant="shadow"
subtitleVariant="shadow"
/>
<View style={[StyleSheet.absoluteFill, styles.cover]} />
<Image style={styles.logo} source={assetSource("banner_logo")} contentFit="contain" priority="high" />
<Col style={styles.textContainer}>
<Row type="center">
<Label style={styles.textContainerFill} type="xl" variant="shadow" color="white" ellipsizeMode="tail">
{conId}
</Label>
</Row>

{!subtitle ? null : (
<Row type="center">
<Label style={styles.textContainerFill} type="compact" variant="shadow" color="white" ellipsizeMode="tail">
{subtitle}
</Label>
</Row>
)}
</Col>
</View>
);
};

const styles = StyleSheet.create({
background: {
...StyleSheet.absoluteFillObject,
opacity: 0.6,
cover: {
backgroundColor: "#00000060",
},
container: {
minHeight: 180,
height: 160,
paddingTop: 15,
paddingHorizontal: 15,
flexDirection: "column-reverse",
},
textContainer: {
paddingTop: 30,
paddingBottom: 5,
},
textContainerFill: {
flex: 1,
},
section: {
marginTop: 0,
},
logo: {
width: "50%",
height: "auto",
maxWidth: 200,
position: "absolute",
top: 25,
right: 25,
bottom: 25,
aspectRatio: 1,
alignSelf: "center",
maxHeight: 130,
},
});
55 changes: 55 additions & 0 deletions src/components/home/GlobalSearch.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { Moment } from "moment/moment";
import React from "react";
import { useTranslation } from "react-i18next";

import { useDealerGroups } from "../../routes/dealers/Dealers.common";
import { useEventSearchGroups } from "../../routes/events/Events.common";
import { HomeProps } from "../../routes/home/Home";
import { DealerDetails, EventDetails, KnowledgeEntryDetails } from "../../store/eurofurence/types";
import { DealersSectionedList } from "../dealers/DealersSectionedList";
import { EventsSectionedList } from "../events/EventsSectionedList";
import { Section } from "../generic/atoms/Section";
import { KbSectionedList } from "../kb/KbSectionedList";

export type GlobalSearchProps = {
navigation: HomeProps["navigation"];
now: Moment;
results: (DealerDetails | EventDetails | KnowledgeEntryDetails)[] | null;
};

export const GlobalSearch = ({ navigation, now, results }: GlobalSearchProps) => {
const { t: tMenu } = useTranslation("Menu");
const { t: tDealers } = useTranslation("Dealers");
const { t: tEvents } = useTranslation("Events");

// Use all dealers and group generically.
const dealersGroups = useDealerGroups(tDealers, now, results?.filter((r) => "RegistrationNumber" in r) as DealerDetails[], []);
const eventGroups = useEventSearchGroups(tEvents, now, results?.filter((r) => "StartDateTimeUtc" in r) as EventDetails[]);
const kbGroups = results?.filter((r) => "KnowledgeGroupId" in r) as KnowledgeEntryDetails[];

if (!results) return null;
return (
<>
{!dealersGroups?.length ? null : (
<DealersSectionedList
navigation={navigation as any}
dealersGroups={dealersGroups}
leader={<Section icon="card-search" title={tMenu("dealers")} />}
padEnd={false}
/>
)}
{!eventGroups?.length ? null : (
<EventsSectionedList
navigation={navigation as any}
eventsGroups={eventGroups}
cardType="time"
leader={<Section icon="card-search" title={tMenu("events")} />}
padEnd={false}
/>
)}
{!kbGroups?.length ? null : (
<KbSectionedList navigation={navigation as any} kbGroups={kbGroups} leader={<Section icon="card-search" title={tMenu("info")} />} padEnd={false} />
)}
</>
);
};
5 changes: 3 additions & 2 deletions src/components/kb/KbSectionedList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ export type KbSectionedListProps = {
empty?: ReactElement;
trailer?: ReactElement;
sticky?: boolean;
padEnd?: boolean;
};

export const KbSectionedList: FC<KbSectionedListProps> = ({ navigation, leader, kbGroups, empty, trailer, sticky = true }) => {
export const KbSectionedList: FC<KbSectionedListProps> = ({ navigation, leader, kbGroups, empty, trailer, sticky = true, padEnd = true }) => {
const theme = useThemeName();
const synchronizer = useSynchronizer();
const stickyIndices = useMemo(() => (sticky ? findIndices(kbGroups, (item) => !("KnowledgeGroupId" in item)) : undefined), [kbGroups, sticky]);
Expand All @@ -32,7 +33,7 @@ export const KbSectionedList: FC<KbSectionedListProps> = ({ navigation, leader,
<FlashList
refreshing={synchronizer.isSynchronizing}
onRefresh={synchronizer.synchronize}
contentContainerStyle={styles.container}
contentContainerStyle={padEnd ? styles.container : undefined}
scrollEnabled={true}
stickyHeaderIndices={stickyIndices}
ListHeaderComponent={leader}
Expand Down
2 changes: 1 addition & 1 deletion src/components/settings/ThemePicker.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import _, { capitalize } from "lodash";
import { capitalize } from "lodash";
import React from "react";
import { useTranslation } from "react-i18next";
import { StyleSheet } from "react-native";
Expand Down
2 changes: 1 addition & 1 deletion src/components/viewer/ViewerImageRecord.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ReactNativeZoomableView as ZoomableView } from "@openspacelabs/react-native-zoomable-view";
import { FC } from "react";
import { useTranslation } from "react-i18next";
import { Dimensions, StyleSheet, View } from "react-native";
import { StyleSheet, View } from "react-native";

import { minZoomFor, shareImage } from "./Viewer.common";
import { useAppSelector } from "../../store";
Expand Down
2 changes: 1 addition & 1 deletion src/components/viewer/ViewerUrl.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ReactNativeZoomableView as ZoomableView } from "@openspacelabs/react-native-zoomable-view";
import { FC, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { Dimensions, StyleSheet, View, Image as ReactImage } from "react-native";
import { StyleSheet, View, Image as ReactImage } from "react-native";

import { minZoomFor, shareImage } from "./Viewer.common";
import { Image } from "../generic/atoms/Image";
Expand Down
Loading

0 comments on commit 746dff7

Please sign in to comment.