Skip to content

Commit

Permalink
added badges
Browse files Browse the repository at this point in the history
  • Loading branch information
xiduzo committed Jun 21, 2024
1 parent 565212b commit 79f2d12
Show file tree
Hide file tree
Showing 22 changed files with 418 additions and 133 deletions.
19 changes: 10 additions & 9 deletions apps/expo/app/fissa/[pin]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ import { useCallback, useState, type FC } from "react";
import { TouchableOpacity, View } from "react-native";

import {
Fab,
FissaTracks,
IconButton,
PageTemplate,
Popover,
QuickVoteProvider,
SelectDevice,
Settings,
Typography,
Fab,
FissaTracks,
IconButton,
PageTemplate,
Popover,
QuickVoteProvider,
SelectDevice,
Settings,
Typography,
} from "../../../src/components";
import { useIsOwner, useOnActiveApp, useShareFissa } from "../../../src/hooks";
import { api, mapDeviceToIcon, toast } from "../../../src/utils";
Expand All @@ -26,6 +26,7 @@ const Fissa = () => {
const { replace } = useRouter();

api.fissa.byId.useQuery(String(pin), {
enabled: !!pin,
onError: (error) => {
toast.error({ message: error.message });
void notificationAsync(NotificationFeedbackType.Error);
Expand Down
31 changes: 3 additions & 28 deletions apps/expo/app/home.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { Stack, useRouter } from "expo-router";
import React, { useCallback, useState, type FC } from "react";
import { View } from "react-native";
import { Stack, useRouter } from "expo-router";

import {
Action,
Button,
ButtonGroup,
Divider,
IconButton,
PageTemplate,
Popover,
Expand Down Expand Up @@ -81,34 +79,11 @@ export default Home;
const headerRight = () => <AccountDetails />;

const AccountDetails = () => {
const [showAccountDetails, setShowAccountDetails] = useState(false);
const { signOut, user } = useAuth();

const toggleAccountDetails = useCallback(() => {
setShowAccountDetails((prev) => !prev);
}, []);

const handleSignOut = useCallback(() => {
toggleAccountDetails();
signOut();
}, [toggleAccountDetails, signOut]);
const { push } = useRouter();

return (
<>
<IconButton title="account details" icon="user" onPress={toggleAccountDetails} />
<Popover visible={showAccountDetails} onRequestClose={toggleAccountDetails}>
<Typography inverted variant="h3" centered>
{user?.display_name}
</Typography>
<Divider />
<Action
icon="user"
title="Sign out"
subtitle="hasta la vista baby"
inverted
onPress={handleSignOut}
/>
</Popover>
<IconButton title="account details" icon="user" onPress={() => push('/profile')} />
</>
);
};
Expand Down
14 changes: 8 additions & 6 deletions apps/expo/app/host/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useCallback } from "react";
import { View } from "react-native";
import { Stack } from "expo-router";
import { randomSort, useSpotify } from "@fissa/utils";
import { Stack } from "expo-router";
import { useCallback, useState } from "react";
import { View } from "react-native";

import { Button, ButtonGroup, PageTemplate, Typography } from "../../src/components";
import { useCreateFissa } from "../../src/hooks";
Expand All @@ -11,17 +11,20 @@ const MAX_SEED_TRACKS = 5;

const Host = () => {
const spotify = useSpotify();
const [isLoading, setIsLoading] = useState(false);

const { mutateAsync, isLoading } = useCreateFissa({
const { mutateAsync } = useCreateFissa({
onSettled: () => {
toast.hide();
setIsLoading(false)
},
});

const handleSurpriseMe = useCallback(async () => {
setIsLoading(true)
toast.info({
icon: "🦔",
message: "An explorer I see, making a fissa just for you",
message: "Explore songs just for you",
duration: 60 * 1000,
});
try {
Expand All @@ -36,7 +39,6 @@ const Host = () => {

await mutateAsync(tracks);
} catch (e) {
console.error(e);
toast.error({
message: "Woops, something went wrong. Try again later.",
});
Expand Down
140 changes: 140 additions & 0 deletions apps/expo/app/profile/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import { theme } from "@fissa/tailwind-config"
import { format, formatNumber } from "@fissa/utils"
import { FlashList } from "@shopify/flash-list"
import { Stack, useRouter } from "expo-router"
import { useCallback, useState } from "react"
import { TouchableHighlight, View } from "react-native"
import { BADGE } from "../../../../packages/db"
import { Button, PageTemplate, Popover, Typography } from "../../src/components"
import { useAuth } from "../../src/providers"
import { api } from "../../src/utils"

const Index = () => {
const { user, signOut } = useAuth()
const { replace } = useRouter()
const { data, isInitialLoading } = api.auth.getUserStats.useQuery()

const signOutUser = useCallback(() => {
signOut()
replace("")
}, [signOut, replace])

return (
<PageTemplate fullScreen className="p-6 pb-8">
<Stack.Screen
options={{
headerShown: true,
headerBackVisible: true
}}
/>
<View className="space-y-10">
<View className="space-y-1">
<Typography centered variant="h1">{user?.display_name}</Typography>
<Typography centered dimmed>Joined {format(data?.createdAt ?? new Date(), "MMMM yyyy")}</Typography>
</View>
<View className="space-y-2">
<View className="justify-between items-center flex-row">
<Typography variant="h2">Stats</Typography>
{/* <Typography dimmed>+2 undiscovered</Typography> */}
</View>
<View className="flex-grow h-80 -mx-2">
<FlashList estimatedItemSize={24} horizontal renderItem={({ item }) => {
return <Badge isLoading={isInitialLoading} badge={item} score={data?.badges.find(badge => badge.name === item)?.score} />
}} data={Object.values(BADGE)} />
</View>
</View>
</View>
<View>
<Button
inverted
title="Sign out"
onPress={signOutUser} />
</View>
</PageTemplate>
)
}

type Badge = { name: string, icon: string, description: string, subtext?: string }
const BADGE_NAMES: Record<BADGE, Badge> = {
[BADGE.DOWN_VOTES_CAST]: {
name: "Critic",
icon: "🐈",
description: "Earned by down voting songs of others"
},
[BADGE.DOWN_VOTES_RECEIVED]: {
name: "Buzzkill",
icon: "🦟",
description: "Earned by receiving down votes on your songs"
},
[BADGE.FISSAS_CREATED]: {
name: "Super host",
icon: "🦃",
description: "Earned by hosting Fissas",
subtext: "Can only earn 1 point per day"
},
[BADGE.FISSAS_JOINED]: {
name: "Party animal",
icon: "🦚",
description: "Earned by joining Fissas",
subtext: "Can only earn 1 point per day"
},
[BADGE.TRACKS_ADDED]: {
name: "Beatmaster",
icon: "🦗",
description: "Earned by adding songs to Fissas"
},
[BADGE.UP_VOTES_CAST]: {
name: "Cheerleader",
icon: "🐄",
description: "Earned by up voting songs of others"
},
[BADGE.UP_VOTES_RECEIVED]: {
name: "Superstar",
icon: "🐩",
description: "Earned by receiving up votes on your songs"
},
[BADGE.POINTS_EARNED]: {
name: "Music Maestro",
icon: "🦜",
description: "Your total Fissa score over all Fissas"
},
}

const Badge = ({ badge, score, isLoading }: { badge: BADGE, isLoading: boolean, score?: number }) => {
const [selected, setSelected] = useState(false)

return (
<View className="mx-2 mb-4">
<TouchableHighlight
className="rounded-md"
onPress={() => setSelected(true)}
underlayColor={theme['100'] + '40'}
>
<View className="items-center border rounded-md w-36 lg:w-56 p-3 space-y-2" style={{
borderColor: theme['100'] + '40',
}}>
<Typography centered dimmed>{BADGE_NAMES[badge].name}</Typography>
<View className="w-24 h-24 lg:w-32 lg:h-32 items-center justify-center">
<Typography centered dimmed className="text-6xl lg:text-7xl" style={{
lineHeight: 70
}}>{BADGE_NAMES[badge].icon}</Typography>
</View>
{!isLoading && <Typography variant='h3'>{formatNumber(score ?? 0)}</Typography>}
{isLoading && <Typography variant='h3' className="w-6 animate-pulse" style={{ backgroundColor: theme['100'] + '10' }}>&nbsp;</Typography>}
</View>
</TouchableHighlight>
<Popover visible={selected} onRequestClose={() => setSelected(false)}>
<Typography variant='h3' inverted centered>{BADGE_NAMES[badge].name}</Typography>
<Typography inverted centered className="pb-14 pt-16 text-6xl">{formatNumber(score ?? 0)}</Typography>
<Typography inverted centered dimmed>
{BADGE_NAMES[badge].description}
</Typography>
{BADGE_NAMES[badge].subtext && <Typography variant='bodyM' className="italic mt-2" inverted centered dimmed>
{BADGE_NAMES[badge].subtext}
</Typography>}
</Popover>
</View>
)
}

export default Index
8 changes: 4 additions & 4 deletions apps/expo/src/components/PageTemplate.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { type FC } from "react";
import { SafeAreaView, View, type ViewProps } from "react-native";
import { theme } from "@fissa/tailwind-config";
import { cva, type VariantProps } from "@fissa/utils";
import { type FC } from "react";
import { SafeAreaView, View, type ViewProps } from "react-native";

export const PageTemplate: FC<Props> = ({ children, className, fullScreen, ...props }) => {
const Wrapper = fullScreen ? View : SafeAreaView;
Expand All @@ -15,7 +15,7 @@ export const PageTemplate: FC<Props> = ({ children, className, fullScreen, ...pr
);
};

interface Props extends ViewProps, VariantProps<typeof pageTemplate> {}
interface Props extends ViewProps, VariantProps<typeof pageTemplate> { }

const pageTemplate = cva("m-auto h-full w-full justify-between", {
variants: {
Expand All @@ -24,7 +24,7 @@ const pageTemplate = cva("m-auto h-full w-full justify-between", {
*/
fullScreen: {
true: "max-w-screen-2xl",
false: "p-6 pb-4 max-w-lg",
false: "p-6 pb-8 max-w-lg",
},
},
defaultVariants: {
Expand Down
48 changes: 25 additions & 23 deletions apps/expo/src/components/pages/fissa/Tracks.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,38 @@
import { theme } from "@fissa/tailwind-config";
import {
AnimationSpeed,
differenceInMilliseconds,
sortFissaTracksOrder,
useDevices,
useTracks,
AnimationSpeed,
differenceInMilliseconds,
sortFissaTracksOrder,
useDevices,
useTracks,
} from "@fissa/utils";
import { type FlashList } from "@shopify/flash-list";
import { NotificationFeedbackType, notificationAsync } from "expo-haptics";
import { useGlobalSearchParams, useRouter } from "expo-router";
import { useCallback, useEffect, useRef, useState, type FC } from "react";
import {
Animated,
TouchableHighlight,
View,
type NativeScrollEvent,
type NativeSyntheticEvent,
Animated,
TouchableHighlight,
View,
type NativeScrollEvent,
type NativeSyntheticEvent,
} from "react-native";

import { useCreateVote, useIsOwner, useOnActiveApp, useSkipTrack } from "../../../hooks";
import { useAuth } from "../../../providers";
import { api } from "../../../utils";
import { QuickVoteModal, useQuickVote } from "../../quickVote";
import {
Action,
Divider,
Icon,
IconButton,
Popover,
ProgressBar,
TrackEnd,
TrackList,
TrackListItem,
Typography,
Action,
Divider,
Icon,
IconButton,
Popover,
ProgressBar,
TrackEnd,
TrackList,
TrackListItem,
Typography,
} from "../../shared";
import { ListEmptyComponent } from "./ListEmptyComponent";
import { ListFooterComponent } from "./ListFooterComponent";
Expand Down Expand Up @@ -292,7 +292,9 @@ interface SelectedTrackPopoverProps {

const TrackActions: FC<TrackActionsProps> = ({ track, onPress }) => {
const { pin } = useGlobalSearchParams();
const { data: fissa } = api.fissa.byId.useQuery(String(pin));
const { data: fissa } = api.fissa.byId.useQuery(String(pin), {
enabled: !!pin,
});

const { push } = useRouter();

Expand All @@ -318,8 +320,8 @@ const TrackActions: FC<TrackActionsProps> = ({ track, onPress }) => {
});

const isActiveTrack = fissa?.currentlyPlayingId === track.id;
const hasBeenPlayed = fissa?.tracks.find(({ trackId }) => trackId === track?.id)?.hasBeenPlayed;
const canRemoveTrack = fissa?.tracks.find(({ trackId }) => trackId === track?.id)?.by?.email === user?.id ?? isOwner
const hasBeenPlayed = fissa?.tracks.find(({ trackId }) => trackId === track?.id)?.hasBeenPlayed;
const canRemoveTrack = (fissa?.tracks.find(({ trackId }) => trackId === track?.id)?.by?.email === user?.email) || isOwner

const handleVote = useCallback(
(vote: number) => async () => {
Expand Down
Loading

0 comments on commit 79f2d12

Please sign in to comment.