Merge branch 'feature/adc/#243-leaderboard' into feat/adc/search-view-v2
This commit is contained in:
@@ -90,7 +90,7 @@ const protectedRoutes = () =>
|
|||||||
},
|
},
|
||||||
Leaderboard: {
|
Leaderboard: {
|
||||||
component: Leaderboardiew,
|
component: Leaderboardiew,
|
||||||
options: { title: translate('leaderboardTitle') },
|
options: { title: translate('leaderboardTitle'), headerShown: false },
|
||||||
link: '/leaderboard',
|
link: '/leaderboard',
|
||||||
},
|
},
|
||||||
Error: {
|
Error: {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const menu = [
|
|||||||
{ type: 'main', title: 'menuProfile', icon: User, link: 'User' },
|
{ type: 'main', title: 'menuProfile', icon: User, link: 'User' },
|
||||||
{ type: 'main', title: 'menuMusic', icon: Music, link: 'Music' },
|
{ type: 'main', title: 'menuMusic', icon: Music, link: 'Music' },
|
||||||
{ type: 'main', title: 'menuSearch', icon: SearchNormal1, link: 'Search' },
|
{ type: 'main', title: 'menuSearch', icon: SearchNormal1, link: 'Search' },
|
||||||
{ type: 'main', title: 'menuLeaderBoard', icon: Cup, link: 'Score' },
|
{ type: 'main', title: 'menuLeaderBoard', icon: Cup, link: 'Leaderboard' },
|
||||||
{ type: 'sub', title: 'menuSettings', icon: Setting2, link: 'Settings' },
|
{ type: 'sub', title: 'menuSettings', icon: Setting2, link: 'Settings' },
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ export const UserValidator = yup
|
|||||||
googleID: yup.string().required().nullable(),
|
googleID: yup.string().required().nullable(),
|
||||||
isGuest: yup.boolean().required(),
|
isGuest: yup.boolean().required(),
|
||||||
partyPlayed: yup.number().required(),
|
partyPlayed: yup.number().required(),
|
||||||
|
totalScore: yup.number().required(),
|
||||||
})
|
})
|
||||||
.concat(ModelValidator);
|
.concat(ModelValidator);
|
||||||
|
|
||||||
@@ -30,6 +31,7 @@ export const UserHandler: ResponseHandler<yup.InferType<typeof UserValidator>, U
|
|||||||
premium: false,
|
premium: false,
|
||||||
data: {
|
data: {
|
||||||
gamesPlayed: value.partyPlayed as number,
|
gamesPlayed: value.partyPlayed as number,
|
||||||
|
totalScore: value.totalScore as number,
|
||||||
xp: 0,
|
xp: 0,
|
||||||
createdAt: new Date('2023-04-09T00:00:00.000Z'),
|
createdAt: new Date('2023-04-09T00:00:00.000Z'),
|
||||||
avatar: `${API.baseUrl}/users/${value.id}/picture`,
|
avatar: `${API.baseUrl}/users/${value.id}/picture`,
|
||||||
@@ -51,7 +53,7 @@ interface User extends Model {
|
|||||||
interface UserData {
|
interface UserData {
|
||||||
gamesPlayed: number;
|
gamesPlayed: number;
|
||||||
xp: number;
|
xp: number;
|
||||||
totalScore: number;
|
totalScore: number;
|
||||||
avatar: string;
|
avatar: string;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ const HomeView = (props: RouteProps<{}>) => {
|
|||||||
translate={{ translationKey: 'leaderboardTitle' }}
|
translate={{ translationKey: 'leaderboardTitle' }}
|
||||||
colorScheme="primary"
|
colorScheme="primary"
|
||||||
size="sm"
|
size="sm"
|
||||||
onPress={() => navigation.navigate('Leaderboard')}
|
onPress={() => navigation.navigate('Leaderboard', {})}
|
||||||
/>
|
/>
|
||||||
<TextButton
|
<TextButton
|
||||||
label={'V2'}
|
label={'V2'}
|
||||||
|
|||||||
+167
-96
@@ -1,8 +1,11 @@
|
|||||||
import { Box, Heading, useBreakpointValue, ScrollView, Text } from 'native-base';
|
import { useBreakpointValue, ScrollView, Text } from 'native-base';
|
||||||
import { View, Image } from 'react-native';
|
import { View, Image } from 'react-native';
|
||||||
import { useQuery } from '../Queries';
|
import { useQuery } from '../Queries';
|
||||||
import API from '../API';
|
import API from '../API';
|
||||||
import { Ionicons } from '@expo/vector-icons';
|
import { LoadingView } from '../components/Loading';
|
||||||
|
import { useNavigation, RouteProps } from '../Navigation';
|
||||||
|
import { MedalStar } from 'iconsax-react-native';
|
||||||
|
import ScaffoldCC from '../components/UI/ScaffoldCC';
|
||||||
import User from '../models/User';
|
import User from '../models/User';
|
||||||
|
|
||||||
type PodiumCardProps = {
|
type PodiumCardProps = {
|
||||||
@@ -10,15 +13,21 @@ type PodiumCardProps = {
|
|||||||
medalColor: string;
|
medalColor: string;
|
||||||
userAvatarUrl: string;
|
userAvatarUrl: string;
|
||||||
userPseudo: string;
|
userPseudo: string;
|
||||||
userXp: number;
|
userLvl: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
const PodiumCardComponent = ({ offset, medalColor, userAvatarUrl, userPseudo, userXp }: PodiumCardProps) => {
|
const PodiumCardComponent = ({
|
||||||
|
offset,
|
||||||
|
medalColor,
|
||||||
|
userAvatarUrl,
|
||||||
|
userPseudo,
|
||||||
|
userLvl,
|
||||||
|
}: PodiumCardProps) => {
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
paddingTop: 0 + offset,
|
paddingTop: offset,
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
@@ -43,10 +52,10 @@ const PodiumCardComponent = ({ offset, medalColor, userAvatarUrl, userPseudo, us
|
|||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Ionicons
|
<MedalStar
|
||||||
style={{ position: 'absolute', top: 106, left: 106 }}
|
style={{ position: 'absolute', top: 115, left: 115 }}
|
||||||
name="medal"
|
size="42"
|
||||||
size={24}
|
variant="Bold"
|
||||||
color={medalColor}
|
color={medalColor}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
@@ -68,22 +77,25 @@ const PodiumCardComponent = ({ offset, medalColor, userAvatarUrl, userPseudo, us
|
|||||||
fontWeight: '500',
|
fontWeight: '500',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{userXp} LVL
|
{userLvl} LVL
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
type BoardRowProps = {
|
type BoardRowProps = {
|
||||||
|
userAvatarUrl: string;
|
||||||
userPseudo: string;
|
userPseudo: string;
|
||||||
userXp: number;
|
userLvl: number;
|
||||||
}
|
index: number;
|
||||||
|
};
|
||||||
|
|
||||||
const BoardRowComponent = () => {
|
const BoardRowComponent = ({ userAvatarUrl, userPseudo, userLvl, index }: BoardRowProps) => {
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
margin: 5,
|
marginVertical: 5,
|
||||||
|
marginHorizontal: 10,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
@@ -105,9 +117,14 @@ const BoardRowComponent = () => {
|
|||||||
>
|
>
|
||||||
<Image
|
<Image
|
||||||
source={{
|
source={{
|
||||||
uri: 'https://picsum.photos/50/50',
|
uri: userAvatarUrl,
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
borderTopLeftRadius: 8,
|
||||||
|
borderBottomLeftRadius: 8,
|
||||||
}}
|
}}
|
||||||
style={{ width: '100%', height: '100%' }}
|
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
@@ -115,12 +132,12 @@ const BoardRowComponent = () => {
|
|||||||
style={{
|
style={{
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontStyle: 'normal',
|
fontStyle: 'normal',
|
||||||
flex: '1 1 0',
|
flex: 1,
|
||||||
marginHorizontal: 10,
|
marginHorizontal: 10,
|
||||||
fontWeight: '500',
|
fontWeight: '500',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Momo est boutain
|
{userPseudo}
|
||||||
</Text>
|
</Text>
|
||||||
<Text
|
<Text
|
||||||
style={{
|
style={{
|
||||||
@@ -130,7 +147,7 @@ const BoardRowComponent = () => {
|
|||||||
marginHorizontal: 10,
|
marginHorizontal: 10,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
200 LVL
|
{userLvl} LVL
|
||||||
</Text>
|
</Text>
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
@@ -151,98 +168,152 @@ const BoardRowComponent = () => {
|
|||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
8
|
{index + 4}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const dummyScores = [
|
const Leaderboardiew = (props: RouteProps<Record<string, never>>) => {
|
||||||
{
|
const navigation = useNavigation();
|
||||||
id: 1,
|
const scoresQuery = useQuery(API.getTopTwentyPlayers());
|
||||||
},
|
const screenSize = useBreakpointValue({ base: 'small', md: 'big' });
|
||||||
{
|
const isPhone = screenSize === 'small';
|
||||||
id: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 6,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 7,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 8,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 9,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const Leaderboardiew = () => {
|
if (scoresQuery.isError) {
|
||||||
const scoresQuery = useQuery(API.getTopTwentyPlayers);
|
navigation.navigate('Error');
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
if (scoresQuery.data === undefined) {
|
||||||
|
return (
|
||||||
|
<ScaffoldCC routeName={props.route.name}>
|
||||||
|
<LoadingView />
|
||||||
|
</ScaffoldCC>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollView style={{ marginBottom: 5 }}>
|
<ScaffoldCC routeName={props.route.name}>
|
||||||
<View
|
<ScrollView style={{ marginBottom: 5 }}>
|
||||||
style={{
|
<View
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
alignItems: 'flex-start',
|
|
||||||
flex: 1,
|
|
||||||
flexGrow: 1,
|
|
||||||
flexShrink: 0,
|
|
||||||
flexBasis: 0,
|
|
||||||
alignSelf: 'stretch',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<View /** podium view */
|
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
paddingBottom: 0,
|
flexDirection: 'column',
|
||||||
justifyContent: 'center',
|
alignItems: 'flex-start',
|
||||||
alignItems: 'center',
|
flex: 1,
|
||||||
|
flexGrow: 1,
|
||||||
|
flexShrink: 0,
|
||||||
|
flexBasis: 0,
|
||||||
alignSelf: 'stretch',
|
alignSelf: 'stretch',
|
||||||
flexDirection: 'row',
|
|
||||||
marginBottom: 20,
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<PodiumCardComponent
|
{!isPhone ? (
|
||||||
medalColor="#AE84FB"
|
<View /** podium view */
|
||||||
offset={80}
|
style={{
|
||||||
userAvatarUrl={scoresQuery.data?.at(2)?.data.avatar ?? "fake image"}
|
display: 'flex',
|
||||||
userPseudo={scoresQuery.data?.at(2)?.name ?? "Momo"}
|
flexDirection: 'row',
|
||||||
userXp={scoresQuery.data?.at(2)?.data.xp ?? 0}
|
justifyContent: 'center',
|
||||||
/>
|
alignItems: 'center',
|
||||||
<PodiumCardComponent
|
alignSelf: 'stretch',
|
||||||
medalColor="#EAD93C"
|
paddingBottom: 10,
|
||||||
offset={0}
|
marginBottom: 20,
|
||||||
userAvatarUrl={scoresQuery.data?.at(0)?.data.avatar ?? "fake image"}
|
}}
|
||||||
userPseudo={scoresQuery.data?.at(0)?.name ?? "Momo"}
|
>
|
||||||
userXp={scoresQuery.data?.at(0)?.data.xp ?? 0}
|
<PodiumCardComponent
|
||||||
/>
|
medalColor="#AE84FB"
|
||||||
<PodiumCardComponent
|
offset={80}
|
||||||
medalColor="#5F74F7"
|
userAvatarUrl={
|
||||||
offset={60}
|
scoresQuery.data?.at(2)?.data.avatar ??
|
||||||
userAvatarUrl={scoresQuery.data?.at(1)?.data.avatar ?? "fake image"}
|
'https://picsum.photos/140/140'
|
||||||
userPseudo={scoresQuery.data?.at(1)?.name ?? "Momo"}
|
}
|
||||||
userXp={scoresQuery.data?.at(1)?.data.xp ?? 0}
|
userPseudo={scoresQuery.data?.at(2)?.name ?? '---'}
|
||||||
/>
|
userLvl={scoresQuery.data?.at(2)?.data.totalScore ?? 42}
|
||||||
|
/>
|
||||||
|
<PodiumCardComponent
|
||||||
|
medalColor="#EAD93C"
|
||||||
|
offset={0}
|
||||||
|
userAvatarUrl={
|
||||||
|
scoresQuery.data?.at(0)?.data.avatar ??
|
||||||
|
'https://picsum.photos/140/140'
|
||||||
|
}
|
||||||
|
userPseudo={scoresQuery.data?.at(0)?.name ?? '---'}
|
||||||
|
userLvl={scoresQuery.data?.at(0)?.data.totalScore ?? 42}
|
||||||
|
/>
|
||||||
|
<PodiumCardComponent
|
||||||
|
medalColor="#5F74F7"
|
||||||
|
offset={60}
|
||||||
|
userAvatarUrl={
|
||||||
|
scoresQuery.data?.at(1)?.data.avatar ??
|
||||||
|
'https://picsum.photos/140/140'
|
||||||
|
}
|
||||||
|
userPseudo={scoresQuery.data?.at(1)?.name ?? '---'}
|
||||||
|
userLvl={scoresQuery.data?.at(1)?.data.totalScore ?? 42}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
) : (
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
alignSelf: 'stretch',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<PodiumCardComponent
|
||||||
|
medalColor="#AE84FB"
|
||||||
|
offset={80}
|
||||||
|
userAvatarUrl={
|
||||||
|
scoresQuery.data?.at(0)?.data.avatar ??
|
||||||
|
'https://picsum.photos/140/140'
|
||||||
|
}
|
||||||
|
userPseudo={scoresQuery.data?.at(0)?.name ?? '---'}
|
||||||
|
userLvl={scoresQuery.data?.at(0)?.data.totalScore ?? 42}
|
||||||
|
/>
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<PodiumCardComponent
|
||||||
|
medalColor="#EAD93C"
|
||||||
|
offset={0}
|
||||||
|
userAvatarUrl={
|
||||||
|
scoresQuery.data?.at(1)?.data.avatar ??
|
||||||
|
'https://picsum.photos/140/140'
|
||||||
|
}
|
||||||
|
userPseudo={scoresQuery.data?.at(1)?.name ?? '---'}
|
||||||
|
userLvl={scoresQuery.data?.at(1)?.data.totalScore ?? 42}
|
||||||
|
/>
|
||||||
|
<PodiumCardComponent
|
||||||
|
medalColor="#5F74F7"
|
||||||
|
offset={60}
|
||||||
|
userAvatarUrl={
|
||||||
|
scoresQuery.data?.at(2)?.data.avatar ??
|
||||||
|
'https://picsum.photos/140/140'
|
||||||
|
}
|
||||||
|
userPseudo={scoresQuery.data?.at(2)?.name ?? '---'}
|
||||||
|
userLvl={scoresQuery.data?.at(2)?.data.totalScore ?? 42}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
{scoresQuery.data.slice(3).map((comp: User, index: number) => (
|
||||||
|
<BoardRowComponent
|
||||||
|
key={index}
|
||||||
|
index={index}
|
||||||
|
userAvatarUrl={comp?.data.avatar ?? 'https://picsum.photos/50/50'}
|
||||||
|
userLvl={comp?.data.totalScore ?? 42}
|
||||||
|
userPseudo={comp?.name ?? '---'}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
</View>
|
</View>
|
||||||
{dummyScores.map((comp, index) => (
|
</ScrollView>
|
||||||
<BoardRowComponent />
|
</ScaffoldCC>
|
||||||
))}
|
|
||||||
</View>
|
|
||||||
</ScrollView>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user