Skip to content

Commit

Permalink
feat(app): display past lianes in home list screen (#97)
Browse files Browse the repository at this point in the history
  • Loading branch information
fferrao authored Aug 24, 2023
1 parent b3821ac commit 6aaa9c7
Show file tree
Hide file tree
Showing 7 changed files with 287 additions and 176 deletions.
7 changes: 3 additions & 4 deletions app/src/api/service/liane.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { sync } from "@/util/store";
import { getTripFromLiane } from "@/components/trip/trip";

export interface LianeService {
list(current?: boolean, cursor?: string, pageSize?: number): Promise<PaginatedResponse<Liane>>;
list(states: string[], cursor?: string, pageSize?: number): Promise<PaginatedResponse<Liane>>;
post(liane: LianeRequest): Promise<Liane>;
match2(filter: LianeSearchFilter): Promise<LianeMatchDisplay>;
pickupLinks(pickup: Ref<RallyingPoint>, lianes: Ref<Liane>[]): Promise<NearestLinks>;
Expand Down Expand Up @@ -51,11 +51,10 @@ export class LianeServiceClient implements LianeService {
async delete(lianeId: string): Promise<void> {
await del(`/liane/${lianeId}`);
}
async list(current: boolean = true, cursor: string | undefined = undefined, pageSize: number = 10) {
let paramString = current ? "?state=NotStarted&state=Started&state=Finished" : "?state=Archived&state=Canceled";
async list(states: string[] = ["NotStarted", "Started"], cursor: string | undefined = undefined, pageSize: number = 10) {
let paramString = states.map((state: string, index: number) => `${index === 0 ? "?" : "&"}state=${state}`).join("");
//TODO cursor
const lianes = await get<PaginatedResponse<Liane>>("/liane" + paramString);
//console.debug(JSON.stringify(lianes));
this.syncWithStorage(lianes.data);
return lianes;
}
Expand Down
36 changes: 27 additions & 9 deletions app/src/components/UserPicture.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useMemo } from "react";
import { Image } from "react-native";
import { Image, StyleProp, ViewStyle } from "react-native";

import { AppIcon } from "@/components/base/AppIcon";
import { Center } from "@/components/base/AppLayout";
Expand All @@ -11,9 +11,12 @@ export interface UserPictureProps {
url: string | null | undefined;
size?: number;
id?: string;
style?: StyleProp<ViewStyle>;
borderWidth?: number;
borderColor?: string;
}

export const UserPicture = ({ url, size = 48, id }: UserPictureProps) => {
export const UserPicture = ({ url, size = 48, id, style, borderWidth = 0, borderColor = "transparent" }: UserPictureProps) => {
const color = useMemo(() => {
if (id) {
const hue = (getUniqueColor(id) + 360) % 360;
Expand All @@ -23,23 +26,38 @@ export const UserPicture = ({ url, size = 48, id }: UserPictureProps) => {
}, [id]);
return (
<Center
style={{
backgroundColor: color,
borderRadius: size,
height: size,
width: size
}}>
style={[
style,
{
backgroundColor: color,
borderRadius: size,
height: size,
width: size
}
]}>
{url ? (
<Image
source={{ uri: url, cache: "reload" }}
style={{
borderWidth: borderWidth,
borderColor: borderColor,
borderRadius: size,
height: size,
width: size
}}
/>
) : (
<AppIcon name={"person-outline"} size={0.6 * size} />
<AppIcon
name={"person-outline"}
size={0.6 * size}
style={{
borderWidth: borderWidth,
borderColor: borderColor,
borderRadius: size,
height: size,
width: size
}}
/>
)}
</Center>
);
Expand Down
13 changes: 8 additions & 5 deletions app/src/components/base/AppIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React from "react";
import { Icon } from "react-native-eva-icons";
import { AppDimensions } from "@/theme/dimensions";
import { ColorValue } from "react-native";
import { AppColorPalettes } from "@/theme/colors";
import { ColorValue, StyleProp, ViewStyle } from "react-native";

import CarQuestionMark from "@/assets/icons/car_question_mark.svg";
import CarCheckMark from "@/assets/icons/car_check_mark.svg";
import CarStrikeThrough from "@/assets/icons/car_strike_through.svg";
Expand All @@ -16,17 +15,21 @@ import PositionOff from "@/assets/icons/position-off.svg";
import RallyingPoint from "@/assets/icons/liane_rallying_point.svg";
import Seat from "@/assets/icons/seat.svg";

import { AppDimensions } from "@/theme/dimensions";
import { AppColorPalettes } from "@/theme/colors";

export type IconName = `${(typeof EvaIconsNames)[number]}-outline` | (typeof EvaIconsNames)[number] | CustomIconName;

export type AppIconProps = {
name: IconName;
color?: ColorValue;
size?: number;
opacity?: number;
style?: StyleProp<ViewStyle>;
};

export function AppIcon({ name, color = AppColorPalettes.gray[800], size = AppDimensions.iconSize, opacity = 1 }: AppIconProps) {
const props = { color, width: size, height: size };
export function AppIcon({ name, color = AppColorPalettes.gray[800], size = AppDimensions.iconSize, opacity = 1, style }: AppIconProps) {
const props = { color, width: size, height: size, style };
switch (name) {
case "car-check-mark":
return <CarCheckMark {...props} />;
Expand Down
102 changes: 60 additions & 42 deletions app/src/components/base/AppTabs.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React from "react";
import { ColorValue, LayoutChangeEvent, StyleSheet, View } from "react-native";
import Animated, { Easing, SharedValue, useAnimatedStyle, useSharedValue, withTiming } from "react-native-reanimated";

import { Column, Row } from "@/components/base/AppLayout";
import { AppPressableOverlay } from "@/components/base/AppPressable";
import { AppText } from "@/components/base/AppText";
import { ColorValue, View } from "react-native";

import { AppColorPalettes, AppColors } from "@/theme/colors";
import React from "react";
import Animated, { Easing, useAnimatedStyle, useSharedValue, withTiming } from "react-native-reanimated";

export interface AppTabsProps {
items: string[];
Expand All @@ -14,64 +16,80 @@ export interface AppTabsProps {
selectedTextColor?: ColorValue;
selectedIndex?: number;
isSelectable?: ((index: number) => boolean) | undefined;
fontSize?: number;
}

export const AppTabs = ({
items,
selectedIndex = 0,
isSelectable,
selectedColor = AppColors.orange,
onSelect,
selectedIndex = 0,
selectedColor = AppColors.orange,
unselectedTextColor = AppColorPalettes.gray[800],
selectedTextColor = AppColorPalettes.gray[800]
selectedTextColor = AppColorPalettes.gray[800],
fontSize = 14
}: AppTabsProps) => {
const offset = useSharedValue(0);
const width = useSharedValue(0);

const translateStyle = useAnimatedStyle(() => ({
transform: [
{
translateX: offset.value
}
],
transform: [{ translateX: offset.value }],
width: width.value
}));

return (
<Column>
<Row>
{items.map((item, index) => {
return (
<AppPressableOverlay
disabled={isSelectable ? !isSelectable(index) : false}
onLayout={event => {
if (index === selectedIndex) {
width.value = withTiming(event.nativeEvent.layout.width, {
duration: 300,
easing: Easing.out(Easing.exp)
});
offset.value = withTiming(event.nativeEvent.layout.x, {
duration: 300,
easing: Easing.out(Easing.ease)
});
}
}}
onPress={() => onSelect(index)}>
<AppText
style={{
paddingHorizontal: 24,
fontWeight: selectedIndex === index ? "bold" : undefined,
paddingVertical: 16,
color: selectedIndex === index ? selectedTextColor : unselectedTextColor
}}>
{item}
</AppText>
</AppPressableOverlay>
);
})}
{items.map((item, index) => (
<AppPressableOverlay
key={index}
disabled={isSelectable ? !isSelectable(index) : false}
onLayout={event => onLayout(event, index, selectedIndex, width, offset)}
onPress={() => onSelect(index)}>
<AppText
style={[
styles.textStyle,
{ fontSize: fontSize },
{ fontWeight: selectedIndex === index ? "bold" : undefined },
{ color: selectedIndex === index ? selectedTextColor : unselectedTextColor }
]}>
{item}
</AppText>
</AppPressableOverlay>
))}
</Row>
<View style={{ borderBottomColor: AppColorPalettes.gray[200], borderBottomWidth: 1 }} />
<Animated.View style={[{ borderRadius: 2, height: 4, backgroundColor: selectedColor, position: "relative", top: -3 }, translateStyle]} />
<View style={styles.underline} />
<Animated.View style={[styles.animatedView, translateStyle, { backgroundColor: selectedColor }]} />
</Column>
);
};

const onLayout = (event: LayoutChangeEvent, index: number, selectedIndex: number, width: SharedValue<number>, offset: SharedValue<number>) => {
if (index === selectedIndex) {
width.value = withTiming(event.nativeEvent.layout.width, {
duration: 300,
easing: Easing.out(Easing.exp)
});
offset.value = withTiming(event.nativeEvent.layout.x, {
duration: 300,
easing: Easing.out(Easing.ease)
});
}
};

const styles = StyleSheet.create({
textStyle: {
paddingHorizontal: 24,
paddingVertical: 16
},
underline: {
borderBottomColor: AppColorPalettes.gray[200],
borderBottomWidth: 1
},
animatedView: {
borderRadius: 2,
height: 4,
position: "relative",
top: -3
}
});
4 changes: 2 additions & 2 deletions app/src/screens/user/ArchivedTripsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ export const LianeHistoryQueryKey = "getLianeHistory";

const ArchivedTripsView = WithFetchPaginatedResponse<Liane>(
({ data, refresh, refreshing }) => {
return <TripListView data={data} isFetching={refreshing} onRefresh={refresh} />;
return <TripListView data={data} isFetching={refreshing} onRefresh={refresh} reverseSort={true} />;
},
repository => repository.liane.list(false),
repository => repository.liane.list(["Finished", "Archived", "Canceled"]),
LianeHistoryQueryKey,
NoHistoryView
);
Expand Down
Loading

0 comments on commit 6aaa9c7

Please sign in to comment.