Skip to content

Commit

Permalink
fix: Dealer search and feedback stuff
Browse files Browse the repository at this point in the history
* Platform share icon, iOS usual style not matching up with Android/MCI, added to all share locations, added definition in icon.
* Header buttons debounced.
* Viewer initial zoom fixed, depadded to match floater spec.
* useDebounce hook added.
* Tab label added to control how tab navigator stuff is displayed.
* Fuse integration increase limit.
* Dealer and event router new tab label used.
* Fixed search issue where an old property name was used.
  • Loading branch information
lukashaertel committed Sep 14, 2024
1 parent cec9e45 commit 6407112
Show file tree
Hide file tree
Showing 15 changed files with 94 additions and 21 deletions.
3 changes: 2 additions & 1 deletion src/components/dealers/DealerContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { Button } from "../generic/containers/Button";
import { ImageExButton } from "../generic/containers/ImageButton";
import { LinkItem } from "../maps/LinkItem";
import { conTimeZone } from "../../configuration";
import { platformShareIcon } from "../generic/atoms/Icon";

const DealerCategories = ({ t, dealer }: { t: TFunction; dealer: DealerDetails }) => {
// Nothing to display for no categories.
Expand Down Expand Up @@ -142,7 +143,7 @@ export const DealerContent: FC<DealerContentProps> = ({ dealer, parentPad = 0, u
</Button>

{!shareButton ? null : (
<Button containerStyle={styles.marginBefore} icon="share" onPress={() => shareDealer(dealer)}>
<Button containerStyle={styles.marginBefore} icon={platformShareIcon} onPress={() => shareDealer(dealer)}>
{t("share")}
</Button>
)}
Expand Down
3 changes: 2 additions & 1 deletion src/components/events/EventContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { Button } from "../generic/containers/Button";
import { ImageExButton } from "../generic/containers/ImageButton";
import { Row } from "../generic/containers/Row";
import { conTimeZone } from "../../configuration";
import { platformShareIcon } from "../generic/atoms/Icon";

/**
* Props to the content.
Expand Down Expand Up @@ -139,7 +140,7 @@ export const EventContent: FC<EventContentProps> = ({ event, parentPad = 0, upda
)}

{!shareButton ? null : (
<Button icon="share" onPress={() => shareEvent(event)}>
<Button icon={platformShareIcon} onPress={() => shareEvent(event)}>
{t("share")}
</Button>
)}
Expand Down
3 changes: 3 additions & 0 deletions src/components/generic/atoms/Icon.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import MaterialCommunityIcon from "@expo/vector-icons/MaterialCommunityIcons";
import { Platform } from "react-native";

export type IconNames = keyof typeof MaterialCommunityIcon.glyphMap;

export const Icon = MaterialCommunityIcon;

export const platformShareIcon: IconNames = Platform.OS === "ios" ? "export-variant" : "share";
33 changes: 33 additions & 0 deletions src/components/generic/atoms/TabLabel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { StyleSheet } from "react-native";
import { Label } from "./Label";

export const tabLabelMaxWidth = 110;

export type TabLabelProps = {
focused: boolean;
children: string;
wide: boolean;
};

export const TabLabel = ({ focused, children, wide }: TabLabelProps) => {
return (
<Label type="bold" style={[focused ? styles.focused : styles.unfocused, wide && styles.wide]} numberOfLines={1} ellipsizeMode="tail">
{children}
</Label>
);
};

const styles = StyleSheet.create({
wide: {
maxWidth: tabLabelMaxWidth,
paddingHorizontal: 5,
},
unfocused: {
maxWidth: tabLabelMaxWidth,
opacity: 0.5,
},
focused: {
maxWidth: tabLabelMaxWidth,
opacity: 1,
},
});
9 changes: 7 additions & 2 deletions src/components/generic/containers/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useThemeBackground, useThemeBorder, useThemeColorValue } from "../../..
import { Continuous } from "../atoms/Continuous";
import { Icon, IconNames } from "../atoms/Icon";
import { Label } from "../atoms/Label";
import { useDebounce } from "../../../hooks/util/useDebounce";
import { Row } from "./Row";

const iconSize = 26;
Expand Down Expand Up @@ -51,9 +52,13 @@ export const Header: FC<HeaderProps> = (props) => {
const styleBorder = useThemeBorder("darken");

const navigation = useNavigation();

const onBack = useDebounce(() => navigation.goBack(), [navigation]);
const onSecondary = useDebounce(() => ("secondaryIcon" in props ? props.secondaryPress() : undefined), [props]);

return (
<Row style={[styles.container, styleBackground, styleBorder, props.style]} type="center" variant="spaced">
<TouchableOpacity hitSlop={backHitSlop} containerStyle={styles.back} onPress={() => navigation.goBack()}>
<TouchableOpacity hitSlop={backHitSlop} containerStyle={styles.back} onPress={onBack}>
<Icon name="chevron-left" size={iconSize} color={colorValue} />
</TouchableOpacity>

Expand All @@ -63,7 +68,7 @@ export const Header: FC<HeaderProps> = (props) => {

{/* Optional secondary action. */}
{!("secondaryIcon" in props) ? null : (
<TouchableOpacity hitSlop={secondaryHitSlop} containerStyle={styles.secondary} onPress={() => props.secondaryPress()}>
<TouchableOpacity hitSlop={secondaryHitSlop} containerStyle={styles.secondary} onPress={onSecondary}>
<Icon name={props.secondaryIcon} size={iconSize} color={colorValue} />
</TouchableOpacity>
)}
Expand Down
7 changes: 4 additions & 3 deletions src/components/viewer/ViewerImageRecord.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import { imagesSelectors } from "../../store/eurofurence/selectors/records";
import { RecordId } from "../../store/eurofurence/types";
import { Image } from "../generic/atoms/Image";
import { Header } from "../generic/containers/Header";
import { platformShareIcon } from "../generic/atoms/Icon";
import { minZoomFor, shareImage } from "./Viewer.common";

const viewerPadding = 40;
const viewerPadding = 20;

export type ViewerImageRecordProps = {
id: RecordId;
Expand All @@ -32,7 +33,7 @@ export const ViewerImageRecord: FC<ViewerImageRecordProps> = ({ id }) => {

return (
<View style={StyleSheet.absoluteFill}>
<Header secondaryIcon="share" secondaryPress={() => image && title && shareImage(image.Url, title)}>
<Header secondaryIcon={platformShareIcon} secondaryPress={() => image && title && shareImage(image.Url, title)}>
{title}
</Header>
{!image ? null : (
Expand All @@ -42,7 +43,7 @@ export const ViewerImageRecord: FC<ViewerImageRecordProps> = ({ id }) => {
contentHeight={image.Height + viewerPadding * 2}
minZoom={minZoom}
maxZoom={maxZoom}
initialZoom={minZoom}
initialZoom={minZoom * 1.2}
bindToBorders={true}
>
<View style={styleContainer}>
Expand Down
10 changes: 4 additions & 6 deletions src/components/viewer/ViewerUrl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import { StyleSheet, View, Image as ReactImage } from "react-native";

import { Image } from "../generic/atoms/Image";
import { Header } from "../generic/containers/Header";
import { platformShareIcon } from "../generic/atoms/Icon";
import { minZoomFor, shareImage } from "./Viewer.common";

const viewerPadding = 40;
const viewerPadding = 20;

export type ViewerUrlProps = {
url: string;
Expand All @@ -24,13 +25,11 @@ export const ViewerUrl: FC<ViewerUrlProps> = ({ url, title }) => {
ReactImage.getSize(
url,
(width, height) => {
console.log("GOT SIZE", width, height);
// Gotten successfully.
setWidth(width);
setHeight(height);
},
() => {
console.log("SIZE FAIL");
// Failed, set to 0 so that expo image starts loading.
setWidth(0);
setHeight(0);
Expand All @@ -44,7 +43,7 @@ export const ViewerUrl: FC<ViewerUrlProps> = ({ url, title }) => {

return (
<View style={StyleSheet.absoluteFill}>
<Header secondaryIcon="share" secondaryPress={() => title && shareImage(url, title)}>
<Header secondaryIcon={platformShareIcon} secondaryPress={() => title && shareImage(url, title)}>
{title ?? t("unspecified")}
</Header>

Expand All @@ -57,7 +56,7 @@ export const ViewerUrl: FC<ViewerUrlProps> = ({ url, title }) => {
contentHeight={height + viewerPadding * 2}
minZoom={minZoom}
maxZoom={maxZoom}
initialZoom={minZoom}
initialZoom={minZoom * 1.2}
bindToBorders={true}
>
<View style={{ width, height }}>
Expand All @@ -68,7 +67,6 @@ export const ViewerUrl: FC<ViewerUrlProps> = ({ url, title }) => {
source={url}
priority="high"
onLoad={(event) => {
console.log("EXPO GOT SIZE", event.source.width, event.source.height);
setWidth(event.source.width);
setHeight(event.source.height);
}}
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/searching/useFuseIntegration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { RootState, useAppSelector } from "../../store";
* @param selector The selector from the app state.
* @param limit Maximum results.
*/
export const useFuseIntegration = <T extends object>(selector: (state: RootState) => Fuse<T>, limit = 30): [string, Dispatch<SetStateAction<string>>, T[] | null] => {
export const useFuseIntegration = <T extends object>(selector: (state: RootState) => Fuse<T>, limit = 100): [string, Dispatch<SetStateAction<string>>, T[] | null] => {
// Search state.
const fuse = useAppSelector(selector);
const [filter, setFilter] = useState("");
Expand Down
6 changes: 6 additions & 0 deletions src/hooks/util/useDebounce.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { DependencyList, useMemo } from "react";
import { debounce } from "lodash";

export const useDebounce = (callback: () => void, deps: DependencyList): (() => void) => {
return useMemo(() => debounce(callback, 1000, { leading: true, trailing: false }), deps);
};
3 changes: 2 additions & 1 deletion src/routes/dealers/DealerItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { useUpdateSinceNote } from "../../hooks/records/useUpdateSinceNote";
import { useLatchTrue } from "../../hooks/util/useLatchTrue";
import { useAppSelector } from "../../store";
import { dealersSelectors } from "../../store/eurofurence/selectors/records";
import { platformShareIcon } from "../../components/generic/atoms/Icon";
import { shareDealer } from "./Dealers.common";

/**
Expand All @@ -34,7 +35,7 @@ export const DealerItem = () => {

return (
<ScrollView style={StyleSheet.absoluteFill} stickyHeaderIndices={[0]} stickyHeaderHiddenOnScroll>
<Header secondaryIcon="share" secondaryPress={() => dealer && shareDealer(dealer)}>
<Header secondaryIcon={platformShareIcon} secondaryPress={() => dealer && shareDealer(dealer)}>
{dealer?.DisplayNameOrAttendeeNickname ?? t("viewing_dealer")}
</Header>
<Floater contentStyle={appStyles.trailer}>{!dealer ? null : <DealerContent dealer={dealer} parentPad={padFloater} updated={showUpdated} />}</Floater>
Expand Down
11 changes: 8 additions & 3 deletions src/routes/dealers/Dealers.common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { TFunction } from "i18next";
import moment, { Moment } from "moment-timezone";

import { useMemo } from "react";
import { Share } from "react-native";
import { Platform, Share } from "react-native";

import { DealerDetailsInstance, dealerInstanceForAny } from "../../components/dealers/DealerCard";
import { dealerSectionForCategory, dealerSectionForLetter, dealerSectionForLocation, DealerSectionProps } from "../../components/dealers/DealerSection";
Expand Down Expand Up @@ -177,12 +177,17 @@ export const useDealerAlphabeticalGroups = (t: TFunction, now: Moment, results:
return result;
}, [t, now, results, all]);
};
export const shareDealer = (dealer: DealerDetails) =>
Share.share(
export const shareDealer = (dealer: DealerDetails) => {
if (Platform.OS === "web") {
console.log("share");
return;
}
return Share.share(
{
title: dealer.DisplayNameOrAttendeeNickname,
url: `${appBase}/Web/Dealers/${dealer.Id}`,
message: `Check out ${dealer.DisplayNameOrAttendeeNickname} on ${conAbbr}!\n${appBase}/Web/Dealers/${dealer.Id}`,
},
{},
).catch(captureException);
};
14 changes: 13 additions & 1 deletion src/routes/dealers/DealersRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Icon } from "../../components/generic/atoms/Icon";
import { useTabStyles } from "../../components/generic/nav/useTabStyles";
import { AreasRouterParamsList } from "../AreasRouter";
import { IndexRouterParamsList } from "../IndexRouter";
import { TabLabel } from "../../components/generic/atoms/TabLabel";
import { DealersAd, DealersAdParams } from "./DealersAd";
import { DealersAll, DealersAllParams } from "./DealersAll";
import { DealersAlpha, DealersAlphaParams } from "./DealersAlpha";
Expand Down Expand Up @@ -88,7 +89,18 @@ export const DealersRouter: FC<DealersRouterProps> = () => {
// If the screens require too much performance we should set detach to true again.
return (
<View style={StyleSheet.absoluteFill}>
<Tab.Navigator initialRouteName="All" initialLayout={layout} sceneContainerStyle={scene}>
<Tab.Navigator
initialRouteName="All"
initialLayout={layout}
sceneContainerStyle={scene}
screenOptions={{
tabBarLabel: ({ focused, children }) => (
<TabLabel wide={false} focused={focused}>
{children}
</TabLabel>
),
}}
>
{defaultScreens}
</Tab.Navigator>
</View>
Expand Down
3 changes: 2 additions & 1 deletion src/routes/events/EventItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { useUpdateSinceNote } from "../../hooks/records/useUpdateSinceNote";
import { useLatchTrue } from "../../hooks/util/useLatchTrue";
import { useAppSelector } from "../../store";
import { eventsSelector } from "../../store/eurofurence/selectors/records";
import { platformShareIcon } from "../../components/generic/atoms/Icon";
import { shareEvent } from "./Events.common";

/**
Expand All @@ -32,7 +33,7 @@ export const EventItem = () => {

return (
<ScrollView style={StyleSheet.absoluteFill} stickyHeaderIndices={[0]} stickyHeaderHiddenOnScroll>
<Header secondaryIcon="share" secondaryPress={() => event && shareEvent(event)}>
<Header secondaryIcon={platformShareIcon} secondaryPress={() => event && shareEvent(event)}>
{event?.Title ?? "Viewing event"}
</Header>
<Floater contentStyle={appStyles.trailer}>{!event ? null : <EventContent event={event} parentPad={padFloater} updated={showUpdated} />}</Floater>
Expand Down
6 changes: 6 additions & 0 deletions src/routes/events/EventsRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { EventDayRecord } from "../../store/eurofurence/types";
import { AreasRouterParamsList } from "../AreasRouter";
import { IndexRouterParamsList } from "../IndexRouter";
import { conTimeZone } from "../../configuration";
import { TabLabel } from "../../components/generic/atoms/TabLabel";
import { PersonalSchedule, PersonalScheduleParams } from "./PersonalSchedule";
import { EventsSearch, EventsSearchParams } from "./EventsSearch";
import { EventsRouterContextProvider, useEventsRouterContext } from "./EventsRouterContext";
Expand Down Expand Up @@ -196,6 +197,11 @@ const EventsRouterContent: FC<EventsRouterProps> = ({ route }) => {
screenOptions={{
tabBarScrollEnabled: scroll,
tabBarItemStyle: scroll ? { width: 110 } : undefined,
tabBarLabel: ({ focused, children }) => (
<TabLabel wide={scroll} focused={focused}>
{children}
</TabLabel>
),
lazy: true,
lazyPreloadDistance: 3,
}}
Expand Down
2 changes: 1 addition & 1 deletion src/store/eurofurence/selectors/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const searchOptions: IFuseOptions<any> = {
*/
const dealerSearchProperties: FuseOptionKey<DealerDetails>[] = [
{
name: "FullName",
name: "DisplayNameOrAttendeeNickname",
weight: 2,
},
{
Expand Down

0 comments on commit 6407112

Please sign in to comment.