Redesign profil with datafake for skills
This commit is contained in:
@@ -1,7 +1,20 @@
|
||||
import { Box, useBreakpointValue, useTheme } from 'native-base';
|
||||
import {
|
||||
Box,
|
||||
Column,
|
||||
Row,
|
||||
Select,
|
||||
useBreakpointValue,
|
||||
useTheme,
|
||||
Text,
|
||||
ScrollView,
|
||||
View,
|
||||
} from 'native-base';
|
||||
import { LineChart } from 'react-native-chart-kit';
|
||||
import SongHistory from '../models/SongHistory';
|
||||
import { useState } from 'react';
|
||||
import { useWindowDimensions } from 'react-native';
|
||||
import CheckboxBase from './UI/CheckboxBase';
|
||||
import { Dataset } from 'react-native-chart-kit/dist/HelperTypes';
|
||||
|
||||
type ScoreGraphProps = {
|
||||
// The result of the call to API.getSongHistory
|
||||
@@ -9,69 +22,205 @@ type ScoreGraphProps = {
|
||||
};
|
||||
|
||||
const formatScoreDate = (playDate: Date): string => {
|
||||
const pad = (n: number) => n.toString().padStart(2, '0');
|
||||
const formattedDate = `${pad(playDate.getDay())}/${pad(playDate.getMonth())}`;
|
||||
const formattedTime = `${pad(playDate.getHours())}:${pad(playDate.getMinutes())}`;
|
||||
return `${formattedDate} ${formattedTime}`;
|
||||
// const formattedDate = `${pad(playDate.getDay())}/${pad(playDate.getMonth())}`;
|
||||
// const formattedTime = `${pad(playDate.getHours())}:${pad(playDate.getMinutes())}`;
|
||||
return `${playDate.getDate()}/${playDate.getMonth()}`;
|
||||
};
|
||||
|
||||
const ScoreGraph = (props: ScoreGraphProps) => {
|
||||
const layout = useWindowDimensions();
|
||||
const [selectedRange, setSelectedRange] = useState('3days');
|
||||
const [displayScore, setDisplayScore] = useState(true);
|
||||
const [displayPedals, setDisplayPedals] = useState(false);
|
||||
const [displayRightHand, setDisplayRightHand] = useState(false);
|
||||
const [displayLeftHand, setDisplayLeftHand] = useState(false);
|
||||
const [displayAccuracy, setDisplayAccuracy] = useState(false);
|
||||
const [displayArpeges, setDisplayArpeges] = useState(false);
|
||||
const [displayChords, setDisplayChords] = useState(false);
|
||||
|
||||
const rangeOptions = [
|
||||
{ label: '3 derniers jours', value: '3days' },
|
||||
{ label: 'Dernière semaine', value: 'week' },
|
||||
{ label: 'Dernier mois', value: 'month' },
|
||||
];
|
||||
const scores = props.songHistory.history.sort((a, b) => {
|
||||
if (a.playDate < b.playDate) {
|
||||
return -1;
|
||||
} else if (a.playDate > b.playDate) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
const filterData = () => {
|
||||
const oneWeekAgo = new Date();
|
||||
const oneMonthAgo = new Date();
|
||||
const threeDaysAgo = new Date();
|
||||
switch (selectedRange) {
|
||||
case 'week':
|
||||
oneWeekAgo.setDate(oneWeekAgo.getDate() - 7);
|
||||
return scores.filter((item) => item.playDate >= oneWeekAgo);
|
||||
case 'month':
|
||||
oneMonthAgo.setMonth(oneMonthAgo.getMonth() - 1);
|
||||
return scores.filter((item) => item.playDate > oneMonthAgo);
|
||||
default:
|
||||
threeDaysAgo.setDate(threeDaysAgo.getDate() - 3);
|
||||
return scores.filter((item) => item.playDate >= threeDaysAgo);
|
||||
}
|
||||
};
|
||||
|
||||
const theme = useTheme();
|
||||
const [containerWidth, setContainerWidth] = useState(0);
|
||||
// We sort the scores by date, asc.
|
||||
// By default, the API returns them in desc.
|
||||
// const pointsToDisplay = props.width / 100;
|
||||
const isSmall = useBreakpointValue({ base: true, md: false });
|
||||
const scores = props.songHistory.history
|
||||
.sort((a, b) => {
|
||||
if (a.playDate < b.playDate) {
|
||||
return -1;
|
||||
} else if (a.playDate > b.playDate) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
})
|
||||
.slice(-10);
|
||||
|
||||
const tempDatasets: Dataset[] = [];
|
||||
|
||||
const skills = [
|
||||
{
|
||||
title: 'Score',
|
||||
value: 'score',
|
||||
data: filterData().map(({ score }) => score),
|
||||
color: '#5f74f7',
|
||||
check: displayScore,
|
||||
setCheck: setDisplayScore,
|
||||
},
|
||||
{
|
||||
title: 'Pedals',
|
||||
value: 'pedals',
|
||||
color: '#ae84fb',
|
||||
data: filterData().map(({ score }) => (score > 100 ? score - 100 : score * 1.4)),
|
||||
check: displayPedals,
|
||||
setCheck: setDisplayPedals,
|
||||
},
|
||||
{
|
||||
title: 'Right hand',
|
||||
value: 'rightHand',
|
||||
data: filterData().map(({ score }) => (score > 10 ? score - 10 : score * 0.2)),
|
||||
color: '#a61455',
|
||||
check: displayRightHand,
|
||||
setCheck: setDisplayRightHand,
|
||||
},
|
||||
{
|
||||
title: 'Left hand',
|
||||
value: 'leftHand',
|
||||
data: filterData().map(({ score }) => (score > 50 ? score - 50 : score * 0.8)),
|
||||
color: '#ed4a51',
|
||||
check: displayLeftHand,
|
||||
setCheck: setDisplayLeftHand,
|
||||
},
|
||||
{
|
||||
title: 'Accuracy',
|
||||
value: 'accuracy',
|
||||
data: filterData().map(({ score }) => (score > 40 ? score - 40 : score * 0.4)),
|
||||
color: '#ff7a72',
|
||||
check: displayAccuracy,
|
||||
setCheck: setDisplayAccuracy,
|
||||
},
|
||||
{
|
||||
title: 'Arpeges',
|
||||
value: 'arpeges',
|
||||
data: filterData().map(({ score }) => (score > 200 ? score - 200 : score * 1.2)),
|
||||
color: '#ead93c',
|
||||
check: displayArpeges,
|
||||
setCheck: setDisplayArpeges,
|
||||
},
|
||||
{
|
||||
title: 'Chords',
|
||||
value: 'chords',
|
||||
data: filterData().map(({ score }) => (score > 50 ? score - 50 : score)),
|
||||
color: '#73d697',
|
||||
check: displayChords,
|
||||
setCheck: setDisplayChords,
|
||||
},
|
||||
];
|
||||
|
||||
for (const skill of skills) {
|
||||
if (skill.check) {
|
||||
tempDatasets.push({
|
||||
data: skill.data,
|
||||
color: () => skill.color,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Box
|
||||
style={{ width: '100%' }}
|
||||
onLayout={(event) => setContainerWidth(event.nativeEvent.layout.width)}
|
||||
>
|
||||
<LineChart
|
||||
data={{
|
||||
labels: isSmall ? [] : scores.map(({ playDate }) => formatScoreDate(playDate)),
|
||||
datasets: [
|
||||
{
|
||||
data: scores.map(({ score }) => score),
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
width={containerWidth}
|
||||
height={200} // Completely arbitrary
|
||||
transparent={true}
|
||||
withDots={false}
|
||||
yAxisSuffix=" pts"
|
||||
chartConfig={{
|
||||
decimalPlaces: 0,
|
||||
color: (opacity = 1) => `rgba(255, 255, 255, ${opacity})`,
|
||||
labelColor: () => theme.colors.white,
|
||||
propsForDots: {
|
||||
r: '6',
|
||||
strokeWidth: '2',
|
||||
},
|
||||
<Column>
|
||||
<Row
|
||||
style={{
|
||||
alignItems: 'center',
|
||||
}}
|
||||
bezier
|
||||
// style={{
|
||||
// margin: 3,
|
||||
// shadowColor: theme.colors.primary[400],
|
||||
// shadowOpacity: 1,
|
||||
// shadowRadius: 20,
|
||||
// borderRadius: CardBorderRadius,
|
||||
// }}
|
||||
/>
|
||||
</Box>
|
||||
>
|
||||
<Text>Skils</Text>
|
||||
<ScrollView horizontal={true}>
|
||||
{skills.map((skill) => (
|
||||
<View key={skill.value} style={{ paddingLeft: 20 }}>
|
||||
<CheckboxBase
|
||||
title={skill.title}
|
||||
value={skill.value}
|
||||
check={skill.check}
|
||||
setCheck={skill.setCheck}
|
||||
/>
|
||||
</View>
|
||||
))}
|
||||
</ScrollView>
|
||||
<Select
|
||||
selectedValue={selectedRange}
|
||||
onValueChange={(itemValue) => setSelectedRange(itemValue)}
|
||||
defaultValue={'3days'}
|
||||
bgColor={'rgba(16,16,20,0.5)'}
|
||||
variant="filled"
|
||||
style={{ display: 'flex', justifyContent: 'center' }}
|
||||
width={layout.width > 650 ? '200' : '100'}
|
||||
>
|
||||
{rangeOptions.map((option) => (
|
||||
<Select.Item key={option.label} label={option.label} value={option.value} />
|
||||
))}
|
||||
</Select>
|
||||
</Row>
|
||||
<Box
|
||||
style={{ width: '100%', marginTop: 20 }}
|
||||
onLayout={(event) => setContainerWidth(event.nativeEvent.layout.width)}
|
||||
>
|
||||
{tempDatasets.length > 0 && (
|
||||
<LineChart
|
||||
data={{
|
||||
labels: isSmall
|
||||
? []
|
||||
: filterData().map(({ playDate }) => formatScoreDate(playDate)),
|
||||
datasets: tempDatasets,
|
||||
}}
|
||||
width={containerWidth}
|
||||
height={300} // Completely arbitrary
|
||||
transparent={true}
|
||||
yAxisSuffix=" pts"
|
||||
chartConfig={{
|
||||
propsForLabels: {
|
||||
fontFamily: 'Lexend',
|
||||
},
|
||||
propsForVerticalLabels: {
|
||||
rotation: -90,
|
||||
},
|
||||
propsForBackgroundLines: {
|
||||
strokeDasharray: '',
|
||||
strokeWidth: '1',
|
||||
color: '#fff000',
|
||||
},
|
||||
decimalPlaces: 0,
|
||||
color: (opacity = 1) => `rgba(255, 255, 255, ${opacity})`,
|
||||
labelColor: () => theme.colors.white,
|
||||
propsForDots: {
|
||||
r: '6',
|
||||
strokeWidth: '2',
|
||||
},
|
||||
}}
|
||||
bezier
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</Column>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -107,12 +107,15 @@ const ButtonBase: React.FC<ButtonProps> = ({
|
||||
>
|
||||
{loading ? (
|
||||
<ActivityIndicator
|
||||
style={styles.content}
|
||||
size="small"
|
||||
color={type === 'outlined' ? '#6075F9' : '#FFFFFF'}
|
||||
/>
|
||||
) : (
|
||||
<View style={styles.content}>
|
||||
{icon && <MyIcon size={'18'} color={type === 'outlined' ? '#6075F9' : '#FFFFFF'}/>}
|
||||
{icon && (
|
||||
<MyIcon size={'18'} color={type === 'outlined' ? '#6075F9' : '#FFFFFF'} />
|
||||
)}
|
||||
{iconImage && <Image source={{ uri: iconImage }} style={styles.icon} />}
|
||||
{title && <Text style={styles.text}>{title}</Text>}
|
||||
</View>
|
||||
|
||||
82
front/components/UI/CheckboxBase.tsx
Normal file
82
front/components/UI/CheckboxBase.tsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, View, StyleProp, ViewStyle } from 'react-native';
|
||||
import InteractiveBase from './InteractiveBase';
|
||||
import { Checkbox } from 'native-base';
|
||||
|
||||
interface CheckboxProps {
|
||||
title: string;
|
||||
value: string;
|
||||
// color: string;
|
||||
check: boolean;
|
||||
setCheck: (value: boolean) => void;
|
||||
style?: StyleProp<ViewStyle>;
|
||||
}
|
||||
|
||||
const CheckboxBase: React.FC<CheckboxProps> = ({
|
||||
title,
|
||||
value,
|
||||
// color,
|
||||
style,
|
||||
check,
|
||||
setCheck,
|
||||
}) => {
|
||||
const styleGlassmorphism = StyleSheet.create({
|
||||
Default: {
|
||||
scale: 1,
|
||||
shadowOpacity: 0.3,
|
||||
shadowRadius: 4.65,
|
||||
elevation: 8,
|
||||
backgroundColor: 'rgba(16,16,20,0.5)',
|
||||
},
|
||||
onHover: {
|
||||
scale: 1.01,
|
||||
shadowOpacity: 0.37,
|
||||
shadowRadius: 7.49,
|
||||
elevation: 12,
|
||||
backgroundColor: 'rgba(16,16,20,0.4)',
|
||||
},
|
||||
onPressed: {
|
||||
scale: 0.99,
|
||||
shadowOpacity: 0.23,
|
||||
shadowRadius: 2.62,
|
||||
elevation: 4,
|
||||
backgroundColor: 'rgba(16,16,20,0.6)',
|
||||
},
|
||||
Disabled: {
|
||||
scale: 1,
|
||||
shadowOpacity: 0.3,
|
||||
shadowRadius: 4.65,
|
||||
elevation: 8,
|
||||
backgroundColor: 'rgba(16,16,20,0.5)',
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<InteractiveBase
|
||||
style={[styles.container, style]}
|
||||
styleAnimate={styleGlassmorphism}
|
||||
onPress={async () => {
|
||||
setCheck(!check);
|
||||
}}
|
||||
>
|
||||
<View style={{ paddingVertical: 5, paddingHorizontal: 10 }}>
|
||||
<Checkbox isChecked={check} style={styles.content} value={value}>
|
||||
{title}
|
||||
</Checkbox>
|
||||
</View>
|
||||
</InteractiveBase>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
borderRadius: 8,
|
||||
},
|
||||
content: {
|
||||
justifyContent: 'center',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
},
|
||||
});
|
||||
|
||||
export default CheckboxBase;
|
||||
@@ -233,7 +233,7 @@ const InteractiveBase: React.FC<InteractiveBaseProps> = ({
|
||||
shadowOpacity: styleAnimate.Disabled.shadowOpacity,
|
||||
shadowRadius: styleAnimate.Disabled.shadowRadius,
|
||||
elevation: styleAnimate.Disabled.elevation,
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Animated.View style={[style, isDisabled ? disableStyle : animatedStyle]}>
|
||||
|
||||
@@ -1,73 +1,112 @@
|
||||
import { LinearGradient } from "expo-linear-gradient";
|
||||
import { Center, Flex, Stack, View, Text, Wrap, Image } from "native-base";
|
||||
import { FunctionComponent } from "react";
|
||||
import { Linking, useWindowDimensions } from "react-native";
|
||||
import ButtonBase from "./ButtonBase";
|
||||
import { translate } from "../../i18n/i18n";
|
||||
import API from "../../API";
|
||||
import SeparatorBase from "./SeparatorBase";
|
||||
import LinkBase from "./LinkBase";
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { Center, Flex, Stack, View, Text, Wrap, Image } from 'native-base';
|
||||
import { FunctionComponent } from 'react';
|
||||
import { Linking, useWindowDimensions } from 'react-native';
|
||||
import ButtonBase from './ButtonBase';
|
||||
import { translate } from '../../i18n/i18n';
|
||||
import API from '../../API';
|
||||
import SeparatorBase from './SeparatorBase';
|
||||
import LinkBase from './LinkBase';
|
||||
import ImageBanner from '../../assets/banner.jpg';
|
||||
|
||||
interface ScaffoldAuthProps {
|
||||
title: string;
|
||||
description: string;
|
||||
form: React.ReactNode[];
|
||||
submitButton: React.ReactNode;
|
||||
link: {text: string, description: string, onPress: () => void};
|
||||
title: string;
|
||||
description: string;
|
||||
form: React.ReactNode[];
|
||||
submitButton: React.ReactNode;
|
||||
link: { text: string; description: string; onPress: () => void };
|
||||
}
|
||||
|
||||
const ScaffoldAuth: FunctionComponent<ScaffoldAuthProps> = ({title, description, form, submitButton, link}) => {
|
||||
const layout = useWindowDimensions();
|
||||
const ScaffoldAuth: FunctionComponent<ScaffoldAuthProps> = ({
|
||||
title,
|
||||
description,
|
||||
form,
|
||||
submitButton,
|
||||
link,
|
||||
}) => {
|
||||
const layout = useWindowDimensions();
|
||||
|
||||
return (
|
||||
<Flex direction='row' justifyContent="space-between" style={{ flex: 1, backgroundColor: '#101014'}}>
|
||||
<Center style={{ flex: 1}}>
|
||||
<View style={{ width: '100%', maxWidth: 420, padding: 16 }}>
|
||||
<Stack space={8} justifyContent="center" alignContent="center" alignItems="center" style={{ width: '100%', paddingBottom: 40}}>
|
||||
<Text fontSize="4xl" textAlign="center">{title}</Text>
|
||||
<Text fontSize="lg" textAlign="center">{description}</Text>
|
||||
</Stack>
|
||||
<Stack space={5} justifyContent="center" alignContent="center" alignItems="center" style={{ width: '100%'}}>
|
||||
<ButtonBase
|
||||
style={{width: '100%'}}
|
||||
type='outlined'
|
||||
iconImage='https://upload.wikimedia.org/wikipedia/commons/thumb/5/53/Google_%22G%22_Logo.svg/2008px-Google_%22G%22_Logo.svg.png'
|
||||
title={translate('continuewithgoogle')}
|
||||
onPress={() => Linking.openURL(`${API.baseUrl}/auth/login/google`)}
|
||||
/>
|
||||
<SeparatorBase>or</SeparatorBase>
|
||||
<Stack space={3} justifyContent="center" alignContent="center" alignItems="center" style={{ width: '100%'}}>
|
||||
{form}
|
||||
</Stack>
|
||||
{submitButton}
|
||||
<Wrap style={{flexDirection: 'row', justifyContent: 'center'}}>
|
||||
<Text>{link.description}</Text>
|
||||
<LinkBase onPress={link.onPress}>
|
||||
{link.text}
|
||||
</LinkBase>
|
||||
</Wrap>
|
||||
</Stack>
|
||||
</View>
|
||||
</Center>
|
||||
{
|
||||
layout.width > 650 ?
|
||||
<View style={{width: '50%', height: '100%', padding: 16}}>
|
||||
<Image
|
||||
source={ImageBanner}
|
||||
alt="banner page"
|
||||
style={{width: '100%', height: '100%', borderRadius: 8}}
|
||||
/>
|
||||
</View>
|
||||
: <></>
|
||||
}
|
||||
<LinearGradient
|
||||
start={{x: 0, y: 0}}
|
||||
end={{x: 1, y: 1}}
|
||||
colors={['#101014', '#6075F9']}
|
||||
style={{top: 0, bottom: 0, right: 0, left: 0, width: '100%', height: '100%', position: 'absolute', zIndex: -2}}
|
||||
/>
|
||||
</Flex>
|
||||
<Flex
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
style={{ flex: 1, backgroundColor: '#101014' }}
|
||||
>
|
||||
<Center style={{ flex: 1 }}>
|
||||
<View style={{ width: '100%', maxWidth: 420, padding: 16 }}>
|
||||
<Stack
|
||||
space={8}
|
||||
justifyContent="center"
|
||||
alignContent="center"
|
||||
alignItems="center"
|
||||
style={{ width: '100%', paddingBottom: 40 }}
|
||||
>
|
||||
<Text fontSize="4xl" textAlign="center">
|
||||
{title}
|
||||
</Text>
|
||||
<Text fontSize="lg" textAlign="center">
|
||||
{description}
|
||||
</Text>
|
||||
</Stack>
|
||||
<Stack
|
||||
space={5}
|
||||
justifyContent="center"
|
||||
alignContent="center"
|
||||
alignItems="center"
|
||||
style={{ width: '100%' }}
|
||||
>
|
||||
<ButtonBase
|
||||
style={{ width: '100%' }}
|
||||
type="outlined"
|
||||
iconImage="https://upload.wikimedia.org/wikipedia/commons/thumb/5/53/Google_%22G%22_Logo.svg/2008px-Google_%22G%22_Logo.svg.png"
|
||||
title={translate('continuewithgoogle')}
|
||||
onPress={() => Linking.openURL(`${API.baseUrl}/auth/login/google`)}
|
||||
/>
|
||||
<SeparatorBase>or</SeparatorBase>
|
||||
<Stack
|
||||
space={3}
|
||||
justifyContent="center"
|
||||
alignContent="center"
|
||||
alignItems="center"
|
||||
style={{ width: '100%' }}
|
||||
>
|
||||
{form}
|
||||
</Stack>
|
||||
{submitButton}
|
||||
<Wrap style={{ flexDirection: 'row', justifyContent: 'center' }}>
|
||||
<Text>{link.description}</Text>
|
||||
<LinkBase onPress={link.onPress}>{link.text}</LinkBase>
|
||||
</Wrap>
|
||||
</Stack>
|
||||
</View>
|
||||
</Center>
|
||||
{layout.width > 650 ? (
|
||||
<View style={{ width: '50%', height: '100%', padding: 16 }}>
|
||||
<Image
|
||||
source={ImageBanner}
|
||||
alt="banner page"
|
||||
style={{ width: '100%', height: '100%', borderRadius: 8 }}
|
||||
/>
|
||||
</View>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
<LinearGradient
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
colors={['#101014', '#6075F9']}
|
||||
style={{
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
position: 'absolute',
|
||||
zIndex: -2,
|
||||
}}
|
||||
/>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -103,7 +103,13 @@ const TextFieldBase: React.FC<TextFieldBaseProps> = ({
|
||||
<InteractiveBase style={[style, { borderRadius: 12 }]} styleAnimate={styleAnimate}>
|
||||
<View style={styles.container}>
|
||||
<View style={styles.iconContainerLeft}>
|
||||
{icon && <MyIcon size={'20'} color={iconColor ? iconColor : isFocused ? '#5f74f7' : '#394694'} variant="Bold"/>}
|
||||
{icon && (
|
||||
<MyIcon
|
||||
size={'20'}
|
||||
color={iconColor ? iconColor : isFocused ? '#5f74f7' : '#394694'}
|
||||
variant="Bold"
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
<Input
|
||||
variant="unstyled"
|
||||
|
||||
@@ -12,7 +12,7 @@ const getInitials = (name: string) => {
|
||||
|
||||
type UserAvatarProps = Pick<Parameters<typeof Avatar>[0], 'size'>;
|
||||
|
||||
const UserAvatar = ({ size }: UserAvatarProps) => {
|
||||
const UserAvatar = ({ size = 'md' }: UserAvatarProps) => {
|
||||
const user = useQuery(API.getUserInfo);
|
||||
const avatarUrl = useMemo(() => {
|
||||
if (!user.data) {
|
||||
@@ -25,7 +25,9 @@ const UserAvatar = ({ size }: UserAvatarProps) => {
|
||||
|
||||
return (
|
||||
<Avatar
|
||||
borderRadius={12}
|
||||
size={size}
|
||||
_image={{ borderRadius: 12 }}
|
||||
source={avatarUrl ? { uri: avatarUrl.toString() } : undefined}
|
||||
style={{ zIndex: 0 }}
|
||||
>
|
||||
|
||||
@@ -33,7 +33,7 @@ const ChangeEmailForm = ({ onSubmit }: ChangeEmailFormProps) => {
|
||||
<TextFormField
|
||||
style={{ marginVertical: 10 }}
|
||||
isRequired
|
||||
icon={(size, color) => <Sms size={size} color={color} variant="Bold" />}
|
||||
icon={Sms}
|
||||
placeholder={translate('oldEmail')}
|
||||
value={formData.oldEmail.value}
|
||||
error={formData.oldEmail.error}
|
||||
@@ -51,7 +51,7 @@ const ChangeEmailForm = ({ onSubmit }: ChangeEmailFormProps) => {
|
||||
style={{ marginVertical: 10 }}
|
||||
isRequired
|
||||
autoComplete="off"
|
||||
icon={(size, color) => <Sms size={size} color={color} variant="Bold" />}
|
||||
icon={Sms}
|
||||
placeholder={translate('newEmail')}
|
||||
value={formData.newEmail.value}
|
||||
error={formData.newEmail.error}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import React from 'react';
|
||||
import { useWindowDimensions, View } from 'react-native';
|
||||
import { Box, Column, Flex, Heading, HStack, Progress, Row, Text, VStack, Wrap } from 'native-base';
|
||||
import { useWindowDimensions } from 'react-native';
|
||||
import { Column, Flex, Progress, Row, Text, Wrap } from 'native-base';
|
||||
import { useNavigation } from '../Navigation';
|
||||
import TextButton from '../components/TextButton';
|
||||
import UserAvatar from '../components/UserAvatar';
|
||||
import { LoadingView } from '../components/Loading';
|
||||
import { useQuery } from '../Queries';
|
||||
@@ -13,107 +12,706 @@ import { translate } from '../i18n/i18n';
|
||||
import ScoreGraph from '../components/ScoreGraph';
|
||||
|
||||
const fakeData = [
|
||||
{score: 47, songID: 34, userID: 1, playDate: new Date("2023-08-20 8:27:21"), difficulties: 1},
|
||||
{score: 1, songID: 603, userID: 1, playDate: new Date("2023-09-13 22:56:45"), difficulties: 1},
|
||||
{score: 93, songID: 601, userID: 1, playDate: new Date("2023-08-11 5:30:13"), difficulties: 5},
|
||||
{score: 55, songID: 456, userID: 1, playDate: new Date("2023-07-10 23:06:09"), difficulties: 4},
|
||||
{score: 2, songID: 345, userID: 1, playDate: new Date("2023-07-23 18:33:24"), difficulties: 2},
|
||||
{score: 47, songID: 625, userID: 1, playDate: new Date("2023-07-09 7:16:46"), difficulties: 1},
|
||||
{score: 27, songID: 234, userID: 1, playDate: new Date("2023-07-06 15:56:53"), difficulties: 5},
|
||||
{score: 85, songID: 866, userID: 1, playDate: new Date("2023-07-08 8:56:44"), difficulties: 2},
|
||||
{score: 28, songID: 484, userID: 1, playDate: new Date("2023-09-12 6:05:32"), difficulties: 4},
|
||||
{score: 5, songID: 443, userID: 1, playDate: new Date("2023-08-01 11:57:09"), difficulties: 3},
|
||||
{score: 14, songID: 109, userID: 1, playDate: new Date("2023-07-03 22:54:07"), difficulties: 3},
|
||||
{score: 57, songID: 892, userID: 1, playDate: new Date("2023-07-13 23:22:34"), difficulties: 5},
|
||||
{score: 7, songID: 164, userID: 1, playDate: new Date("2023-07-02 0:15:13"), difficulties: 2},
|
||||
{score: 42, songID: 761, userID: 1, playDate: new Date("2023-07-10 18:25:19"), difficulties: 3},
|
||||
{score: 49, songID: 82, userID: 1, playDate: new Date("2023-09-12 12:51:15"), difficulties: 4},
|
||||
{score: 83, songID: 488, userID: 1, playDate: new Date("2023-08-28 7:56:31"), difficulties: 5},
|
||||
{score: 91, songID: 648, userID: 1, playDate: new Date("2023-07-21 10:16:33"), difficulties: 4},
|
||||
{score: 67, songID: 210, userID: 1, playDate: new Date("2023-09-14 8:04:50"), difficulties: 1},
|
||||
{score: 31, songID: 274, userID: 1, playDate: new Date("2023-07-10 11:24:28"), difficulties: 4},
|
||||
{score: 29, songID: 930, userID: 1, playDate: new Date("2023-08-06 0:05:43"), difficulties: 5},
|
||||
{score: 51, songID: 496, userID: 1, playDate: new Date("2023-08-14 9:43:14"), difficulties: 1},
|
||||
{score: 56, songID: 370, userID: 1, playDate: new Date("2023-08-18 19:25:59"), difficulties: 2},
|
||||
{score: 29, songID: 333, userID: 1, playDate: new Date("2023-07-11 4:26:44"), difficulties: 4},
|
||||
{score: 95, songID: 921, userID: 1, playDate: new Date("2023-08-30 12:58:50"), difficulties: 1},
|
||||
{score: 37, songID: 80, userID: 1, playDate: new Date("2023-07-16 7:17:57"), difficulties: 4},
|
||||
{score: 90, songID: 134, userID: 1, playDate: new Date("2023-09-03 9:00:04"), difficulties: 1},
|
||||
{score: 51, songID: 497, userID: 1, playDate: new Date("2023-07-31 19:34:43"), difficulties: 4},
|
||||
{score: 95, songID: 368, userID: 1, playDate: new Date("2023-09-12 20:12:50"), difficulties: 4},
|
||||
{score: 55, songID: 247, userID: 1, playDate: new Date("2023-09-16 2:45:13"), difficulties: 1},
|
||||
{score: 26, songID: 725, userID: 1, playDate: new Date("2023-07-28 22:59:31"), difficulties: 2},
|
||||
{score: 82, songID: 952, userID: 1, playDate: new Date("2023-08-01 6:31:47"), difficulties: 1},
|
||||
{score: 88, songID: 85, userID: 1, playDate: new Date("2023-08-12 2:33:11"), difficulties: 5},
|
||||
{score: 12, songID: 96, userID: 1, playDate: new Date("2023-09-03 14:00:33"), difficulties: 4},
|
||||
{score: 100, songID: 807, userID: 1, playDate: new Date("2023-07-03 0:53:11"), difficulties: 3},
|
||||
{score: 88, songID: 456, userID: 1, playDate: new Date("2023-08-06 9:17:15"), difficulties: 5},
|
||||
{score: 10, songID: 889, userID: 1, playDate: new Date("2023-08-15 12:19:16"), difficulties: 3},
|
||||
{score: 76, songID: 144, userID: 1, playDate: new Date("2023-09-10 2:56:49"), difficulties: 4},
|
||||
{score: 60, songID: 808, userID: 1, playDate: new Date("2023-07-24 10:22:33"), difficulties: 1},
|
||||
{score: 94, songID: 537, userID: 1, playDate: new Date("2023-08-03 23:22:29"), difficulties: 2},
|
||||
{score: 100, songID: 465, userID: 1, playDate: new Date("2023-09-16 19:12:58"), difficulties: 2},
|
||||
{score: 85, songID: 31, userID: 1, playDate: new Date("2023-08-17 5:29:49"), difficulties: 2},
|
||||
{score: 98, songID: 345, userID: 1, playDate: new Date("2023-09-11 1:51:49"), difficulties: 1},
|
||||
{score: 81, songID: 204, userID: 1, playDate: new Date("2023-08-21 2:46:56"), difficulties: 2},
|
||||
{score: 21, songID: 40, userID: 1, playDate: new Date("2023-07-27 4:00:00"), difficulties: 2},
|
||||
{score: 91, songID: 274, userID: 1, playDate: new Date("2023-07-14 16:09:49"), difficulties: 5},
|
||||
{score: 99, songID: 416, userID: 1, playDate: new Date("2023-08-27 1:56:16"), difficulties: 5},
|
||||
{score: 58, songID: 87, userID: 1, playDate: new Date("2023-09-08 19:30:20"), difficulties: 5},
|
||||
{score: 90, songID: 744, userID: 1, playDate: new Date("2023-08-18 23:47:55"), difficulties: 2},
|
||||
{score: 69, songID: 954, userID: 1, playDate: new Date("2023-08-07 1:55:52"), difficulties: 5},
|
||||
{score: 75, songID: 467, userID: 1, playDate: new Date("2023-07-10 8:37:22"), difficulties: 4},
|
||||
{score: 41, songID: 693, userID: 1, playDate: new Date("2023-09-11 5:15:16"), difficulties: 2},
|
||||
{score: 56, songID: 140, userID: 1, playDate: new Date("2023-08-06 5:32:46"), difficulties: 2},
|
||||
{score: 88, songID: 64, userID: 1, playDate: new Date("2023-07-31 20:24:30"), difficulties: 1},
|
||||
{score: 99, songID: 284, userID: 1, playDate: new Date("2023-08-07 17:51:19"), difficulties: 5},
|
||||
{score: 47, songID: 746, userID: 1, playDate: new Date("2023-07-18 17:45:56"), difficulties: 5},
|
||||
{score: 80, songID: 791, userID: 1, playDate: new Date("2023-08-21 1:19:45"), difficulties: 1},
|
||||
{score: 21, songID: 748, userID: 1, playDate: new Date("2023-07-04 9:09:27"), difficulties: 4},
|
||||
{score: 75, songID: 541, userID: 1, playDate: new Date("2023-09-19 23:08:05"), difficulties: 2},
|
||||
{score: 31, songID: 724, userID: 1, playDate: new Date("2023-07-09 2:01:29"), difficulties: 4},
|
||||
{score: 24, songID: 654, userID: 1, playDate: new Date("2023-09-04 1:27:00"), difficulties: 1},
|
||||
{score: 55, songID: 154, userID: 1, playDate: new Date("2023-07-10 17:48:17"), difficulties: 3},
|
||||
{score: 4, songID: 645, userID: 1, playDate: new Date("2023-09-11 18:51:11"), difficulties: 2},
|
||||
{score: 52, songID: 457, userID: 1, playDate: new Date("2023-07-30 19:12:52"), difficulties: 3},
|
||||
{score: 68, songID: 236, userID: 1, playDate: new Date("2023-08-08 8:56:08"), difficulties: 3},
|
||||
{score: 44, songID: 16, userID: 1, playDate: new Date("2023-07-22 10:39:34"), difficulties: 1},
|
||||
{score: 59, songID: 863, userID: 1, playDate: new Date("2023-09-17 4:12:43"), difficulties: 1},
|
||||
{score: 18, songID: 276, userID: 1, playDate: new Date("2023-07-08 15:47:54"), difficulties: 2},
|
||||
{score: 64, songID: 557, userID: 1, playDate: new Date("2023-08-17 0:13:46"), difficulties: 1},
|
||||
{score: 2, songID: 452, userID: 1, playDate: new Date("2023-07-26 5:13:31"), difficulties: 5},
|
||||
{score: 99, songID: 546, userID: 1, playDate: new Date("2023-07-11 16:31:37"), difficulties: 1},
|
||||
{score: 75, songID: 598, userID: 1, playDate: new Date("2023-08-12 22:56:24"), difficulties: 4},
|
||||
{score: 4, songID: 258, userID: 1, playDate: new Date("2023-09-20 8:26:50"), difficulties: 2},
|
||||
{score: 50, songID: 190, userID: 1, playDate: new Date("2023-09-20 20:07:06"), difficulties: 4},
|
||||
{score: 9, songID: 914, userID: 1, playDate: new Date("2023-08-30 16:57:14"), difficulties: 5},
|
||||
{score: 7, songID: 92, userID: 1, playDate: new Date("2023-07-18 20:33:44"), difficulties: 5},
|
||||
{score: 94, songID: 98, userID: 1, playDate: new Date("2023-08-15 5:05:18"), difficulties: 5},
|
||||
{score: 94, songID: 424, userID: 1, playDate: new Date("2023-07-22 9:59:12"), difficulties: 5},
|
||||
{score: 14, songID: 635, userID: 1, playDate: new Date("2023-07-02 6:58:39"), difficulties: 4},
|
||||
{score: 99, songID: 893, userID: 1, playDate: new Date("2023-08-05 16:09:33"), difficulties: 1},
|
||||
{score: 94, songID: 67, userID: 1, playDate: new Date("2023-07-01 8:11:37"), difficulties: 2},
|
||||
{score: 21, songID: 335, userID: 1, playDate: new Date("2023-08-03 2:07:44"), difficulties: 3},
|
||||
{score: 47, songID: 294, userID: 1, playDate: new Date("2023-09-13 17:32:46"), difficulties: 4},
|
||||
{score: 89, songID: 184, userID: 1, playDate: new Date("2023-07-04 5:20:13"), difficulties: 2},
|
||||
{score: 28, songID: 345, userID: 1, playDate: new Date("2023-09-07 6:35:11"), difficulties: 3},
|
||||
{score: 93, songID: 697, userID: 1, playDate: new Date("2023-07-29 0:07:10"), difficulties: 2},
|
||||
{score: 58, songID: 666, userID: 1, playDate: new Date("2023-07-09 3:03:02"), difficulties: 2},
|
||||
{score: 73, songID: 459, userID: 1, playDate: new Date("2023-08-05 7:33:54"), difficulties: 4},
|
||||
{score: 50, songID: 695, userID: 1, playDate: new Date("2023-07-26 18:26:55"), difficulties: 4},
|
||||
{score: 39, songID: 995, userID: 1, playDate: new Date("2023-08-24 17:34:09"), difficulties: 3},
|
||||
{score: 25, songID: 122, userID: 1, playDate: new Date("2023-08-25 18:54:12"), difficulties: 1},
|
||||
{score: 29, songID: 439, userID: 1, playDate: new Date("2023-09-15 0:44:48"), difficulties: 3},
|
||||
{score: 79, songID: 234, userID: 1, playDate: new Date("2023-09-13 13:53:16"), difficulties: 2},
|
||||
{score: 0, songID: 369, userID: 1, playDate: new Date("2023-08-30 22:54:34"), difficulties: 1},
|
||||
{score: 25, songID: 223, userID: 1, playDate: new Date("2023-09-13 1:09:11"), difficulties: 3},
|
||||
{score: 55, songID: 716, userID: 1, playDate: new Date("2023-07-12 19:43:23"), difficulties: 3},
|
||||
{score: 100, songID: 62, userID: 1, playDate: new Date("2023-07-11 15:33:40"), difficulties: 5},
|
||||
{score: 74, songID: 271, userID: 1, playDate: new Date("2023-08-25 23:14:51"), difficulties: 3},
|
||||
{score: 22, songID: 265, userID: 1, playDate: new Date("2023-07-17 15:01:38"), difficulties: 1},
|
||||
{score: 79, songID: 552, userID: 1, playDate: new Date("2023-07-28 20:13:14"), difficulties: 5},
|
||||
{score: 50, songID: 603, userID: 1, playDate: new Date("2023-07-06 3:52:21"), difficulties: 5},
|
||||
|
||||
{
|
||||
score: 47,
|
||||
songID: 34,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-20 8:27:21'),
|
||||
difficulties: 1,
|
||||
},
|
||||
{
|
||||
score: 1,
|
||||
songID: 603,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-09-13 22:56:45'),
|
||||
difficulties: 1,
|
||||
},
|
||||
{
|
||||
score: 93,
|
||||
songID: 601,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-11 5:30:13'),
|
||||
difficulties: 5,
|
||||
},
|
||||
{
|
||||
score: 55,
|
||||
songID: 456,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-10 23:06:09'),
|
||||
difficulties: 4,
|
||||
},
|
||||
{
|
||||
score: 2,
|
||||
songID: 345,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-23 18:33:24'),
|
||||
difficulties: 2,
|
||||
},
|
||||
{
|
||||
score: 47,
|
||||
songID: 625,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-09 7:16:46'),
|
||||
difficulties: 1,
|
||||
},
|
||||
{
|
||||
score: 27,
|
||||
songID: 234,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-06 15:56:53'),
|
||||
difficulties: 5,
|
||||
},
|
||||
{
|
||||
score: 85,
|
||||
songID: 866,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-08 8:56:44'),
|
||||
difficulties: 2,
|
||||
},
|
||||
{
|
||||
score: 28,
|
||||
songID: 484,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-09-12 6:05:32'),
|
||||
difficulties: 4,
|
||||
},
|
||||
{
|
||||
score: 5,
|
||||
songID: 443,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-01 11:57:09'),
|
||||
difficulties: 3,
|
||||
},
|
||||
{
|
||||
score: 14,
|
||||
songID: 109,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-03 22:54:07'),
|
||||
difficulties: 3,
|
||||
},
|
||||
{
|
||||
score: 57,
|
||||
songID: 892,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-13 23:22:34'),
|
||||
difficulties: 5,
|
||||
},
|
||||
{
|
||||
score: 7,
|
||||
songID: 164,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-02 0:15:13'),
|
||||
difficulties: 2,
|
||||
},
|
||||
{
|
||||
score: 42,
|
||||
songID: 761,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-10 18:25:19'),
|
||||
difficulties: 3,
|
||||
},
|
||||
{
|
||||
score: 49,
|
||||
songID: 82,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-09-12 12:51:15'),
|
||||
difficulties: 4,
|
||||
},
|
||||
{
|
||||
score: 83,
|
||||
songID: 488,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-28 7:56:31'),
|
||||
difficulties: 5,
|
||||
},
|
||||
{
|
||||
score: 91,
|
||||
songID: 648,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-21 10:16:33'),
|
||||
difficulties: 4,
|
||||
},
|
||||
{
|
||||
score: 67,
|
||||
songID: 210,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-09-14 8:04:50'),
|
||||
difficulties: 1,
|
||||
},
|
||||
{
|
||||
score: 31,
|
||||
songID: 274,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-10 11:24:28'),
|
||||
difficulties: 4,
|
||||
},
|
||||
{
|
||||
score: 29,
|
||||
songID: 930,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-06 0:05:43'),
|
||||
difficulties: 5,
|
||||
},
|
||||
{
|
||||
score: 51,
|
||||
songID: 496,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-14 9:43:14'),
|
||||
difficulties: 1,
|
||||
},
|
||||
{
|
||||
score: 56,
|
||||
songID: 370,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-18 19:25:59'),
|
||||
difficulties: 2,
|
||||
},
|
||||
{
|
||||
score: 29,
|
||||
songID: 333,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-11 4:26:44'),
|
||||
difficulties: 4,
|
||||
},
|
||||
{
|
||||
score: 95,
|
||||
songID: 921,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-30 12:58:50'),
|
||||
difficulties: 1,
|
||||
},
|
||||
{
|
||||
score: 37,
|
||||
songID: 80,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-16 7:17:57'),
|
||||
difficulties: 4,
|
||||
},
|
||||
{
|
||||
score: 90,
|
||||
songID: 134,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-09-03 9:00:04'),
|
||||
difficulties: 1,
|
||||
},
|
||||
{
|
||||
score: 51,
|
||||
songID: 497,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-31 19:34:43'),
|
||||
difficulties: 4,
|
||||
},
|
||||
{
|
||||
score: 95,
|
||||
songID: 368,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-09-12 20:12:50'),
|
||||
difficulties: 4,
|
||||
},
|
||||
{
|
||||
score: 55,
|
||||
songID: 247,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-09-16 2:45:13'),
|
||||
difficulties: 1,
|
||||
},
|
||||
{
|
||||
score: 26,
|
||||
songID: 725,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-28 22:59:31'),
|
||||
difficulties: 2,
|
||||
},
|
||||
{
|
||||
score: 82,
|
||||
songID: 952,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-01 6:31:47'),
|
||||
difficulties: 1,
|
||||
},
|
||||
{
|
||||
score: 88,
|
||||
songID: 85,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-12 2:33:11'),
|
||||
difficulties: 5,
|
||||
},
|
||||
{
|
||||
score: 12,
|
||||
songID: 96,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-09-03 14:00:33'),
|
||||
difficulties: 4,
|
||||
},
|
||||
{
|
||||
score: 100,
|
||||
songID: 807,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-03 0:53:11'),
|
||||
difficulties: 3,
|
||||
},
|
||||
{
|
||||
score: 88,
|
||||
songID: 456,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-06 9:17:15'),
|
||||
difficulties: 5,
|
||||
},
|
||||
{
|
||||
score: 10,
|
||||
songID: 889,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-15 12:19:16'),
|
||||
difficulties: 3,
|
||||
},
|
||||
{
|
||||
score: 76,
|
||||
songID: 144,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-09-10 2:56:49'),
|
||||
difficulties: 4,
|
||||
},
|
||||
{
|
||||
score: 60,
|
||||
songID: 808,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-24 10:22:33'),
|
||||
difficulties: 1,
|
||||
},
|
||||
{
|
||||
score: 94,
|
||||
songID: 537,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-03 23:22:29'),
|
||||
difficulties: 2,
|
||||
},
|
||||
{
|
||||
score: 100,
|
||||
songID: 465,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-09-16 19:12:58'),
|
||||
difficulties: 2,
|
||||
},
|
||||
{
|
||||
score: 85,
|
||||
songID: 31,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-17 5:29:49'),
|
||||
difficulties: 2,
|
||||
},
|
||||
{
|
||||
score: 98,
|
||||
songID: 345,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-09-11 1:51:49'),
|
||||
difficulties: 1,
|
||||
},
|
||||
{
|
||||
score: 81,
|
||||
songID: 204,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-21 2:46:56'),
|
||||
difficulties: 2,
|
||||
},
|
||||
{
|
||||
score: 21,
|
||||
songID: 40,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-27 4:00:00'),
|
||||
difficulties: 2,
|
||||
},
|
||||
{
|
||||
score: 91,
|
||||
songID: 274,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-14 16:09:49'),
|
||||
difficulties: 5,
|
||||
},
|
||||
{
|
||||
score: 99,
|
||||
songID: 416,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-27 1:56:16'),
|
||||
difficulties: 5,
|
||||
},
|
||||
{
|
||||
score: 58,
|
||||
songID: 87,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-09-08 19:30:20'),
|
||||
difficulties: 5,
|
||||
},
|
||||
{
|
||||
score: 90,
|
||||
songID: 744,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-18 23:47:55'),
|
||||
difficulties: 2,
|
||||
},
|
||||
{
|
||||
score: 69,
|
||||
songID: 954,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-07 1:55:52'),
|
||||
difficulties: 5,
|
||||
},
|
||||
{
|
||||
score: 75,
|
||||
songID: 467,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-10 8:37:22'),
|
||||
difficulties: 4,
|
||||
},
|
||||
{
|
||||
score: 41,
|
||||
songID: 693,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-09-11 5:15:16'),
|
||||
difficulties: 2,
|
||||
},
|
||||
{
|
||||
score: 56,
|
||||
songID: 140,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-06 5:32:46'),
|
||||
difficulties: 2,
|
||||
},
|
||||
{
|
||||
score: 88,
|
||||
songID: 64,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-31 20:24:30'),
|
||||
difficulties: 1,
|
||||
},
|
||||
{
|
||||
score: 99,
|
||||
songID: 284,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-07 17:51:19'),
|
||||
difficulties: 5,
|
||||
},
|
||||
{
|
||||
score: 47,
|
||||
songID: 746,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-18 17:45:56'),
|
||||
difficulties: 5,
|
||||
},
|
||||
{
|
||||
score: 80,
|
||||
songID: 791,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-21 1:19:45'),
|
||||
difficulties: 1,
|
||||
},
|
||||
{
|
||||
score: 21,
|
||||
songID: 748,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-04 9:09:27'),
|
||||
difficulties: 4,
|
||||
},
|
||||
{
|
||||
score: 75,
|
||||
songID: 541,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-09-19 23:08:05'),
|
||||
difficulties: 2,
|
||||
},
|
||||
{
|
||||
score: 31,
|
||||
songID: 724,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-09 2:01:29'),
|
||||
difficulties: 4,
|
||||
},
|
||||
{
|
||||
score: 24,
|
||||
songID: 654,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-09-04 1:27:00'),
|
||||
difficulties: 1,
|
||||
},
|
||||
{
|
||||
score: 55,
|
||||
songID: 154,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-10 17:48:17'),
|
||||
difficulties: 3,
|
||||
},
|
||||
{
|
||||
score: 4,
|
||||
songID: 645,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-09-11 18:51:11'),
|
||||
difficulties: 2,
|
||||
},
|
||||
{
|
||||
score: 52,
|
||||
songID: 457,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-30 19:12:52'),
|
||||
difficulties: 3,
|
||||
},
|
||||
{
|
||||
score: 68,
|
||||
songID: 236,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-08 8:56:08'),
|
||||
difficulties: 3,
|
||||
},
|
||||
{
|
||||
score: 44,
|
||||
songID: 16,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-22 10:39:34'),
|
||||
difficulties: 1,
|
||||
},
|
||||
{
|
||||
score: 59,
|
||||
songID: 863,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-09-17 4:12:43'),
|
||||
difficulties: 1,
|
||||
},
|
||||
{
|
||||
score: 18,
|
||||
songID: 276,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-08 15:47:54'),
|
||||
difficulties: 2,
|
||||
},
|
||||
{
|
||||
score: 64,
|
||||
songID: 557,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-17 0:13:46'),
|
||||
difficulties: 1,
|
||||
},
|
||||
{
|
||||
score: 2,
|
||||
songID: 452,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-26 5:13:31'),
|
||||
difficulties: 5,
|
||||
},
|
||||
{
|
||||
score: 99,
|
||||
songID: 546,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-11 16:31:37'),
|
||||
difficulties: 1,
|
||||
},
|
||||
{
|
||||
score: 75,
|
||||
songID: 598,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-12 22:56:24'),
|
||||
difficulties: 4,
|
||||
},
|
||||
{
|
||||
score: 4,
|
||||
songID: 258,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-09-20 8:26:50'),
|
||||
difficulties: 2,
|
||||
},
|
||||
{
|
||||
score: 50,
|
||||
songID: 190,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-09-20 20:07:06'),
|
||||
difficulties: 4,
|
||||
},
|
||||
{
|
||||
score: 9,
|
||||
songID: 914,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-30 16:57:14'),
|
||||
difficulties: 5,
|
||||
},
|
||||
{
|
||||
score: 7,
|
||||
songID: 92,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-18 20:33:44'),
|
||||
difficulties: 5,
|
||||
},
|
||||
{
|
||||
score: 94,
|
||||
songID: 98,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-15 5:05:18'),
|
||||
difficulties: 5,
|
||||
},
|
||||
{
|
||||
score: 94,
|
||||
songID: 424,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-22 9:59:12'),
|
||||
difficulties: 5,
|
||||
},
|
||||
{
|
||||
score: 14,
|
||||
songID: 635,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-02 6:58:39'),
|
||||
difficulties: 4,
|
||||
},
|
||||
{
|
||||
score: 99,
|
||||
songID: 893,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-05 16:09:33'),
|
||||
difficulties: 1,
|
||||
},
|
||||
{
|
||||
score: 94,
|
||||
songID: 67,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-01 8:11:37'),
|
||||
difficulties: 2,
|
||||
},
|
||||
{
|
||||
score: 21,
|
||||
songID: 335,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-03 2:07:44'),
|
||||
difficulties: 3,
|
||||
},
|
||||
{
|
||||
score: 47,
|
||||
songID: 294,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-09-13 17:32:46'),
|
||||
difficulties: 4,
|
||||
},
|
||||
{
|
||||
score: 89,
|
||||
songID: 184,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-04 5:20:13'),
|
||||
difficulties: 2,
|
||||
},
|
||||
{
|
||||
score: 28,
|
||||
songID: 345,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-09-07 6:35:11'),
|
||||
difficulties: 3,
|
||||
},
|
||||
{
|
||||
score: 93,
|
||||
songID: 697,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-29 0:07:10'),
|
||||
difficulties: 2,
|
||||
},
|
||||
{
|
||||
score: 58,
|
||||
songID: 666,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-09 3:03:02'),
|
||||
difficulties: 2,
|
||||
},
|
||||
{
|
||||
score: 73,
|
||||
songID: 459,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-05 7:33:54'),
|
||||
difficulties: 4,
|
||||
},
|
||||
{
|
||||
score: 50,
|
||||
songID: 695,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-26 18:26:55'),
|
||||
difficulties: 4,
|
||||
},
|
||||
{
|
||||
score: 39,
|
||||
songID: 995,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-24 17:34:09'),
|
||||
difficulties: 3,
|
||||
},
|
||||
{
|
||||
score: 25,
|
||||
songID: 122,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-25 18:54:12'),
|
||||
difficulties: 1,
|
||||
},
|
||||
{
|
||||
score: 29,
|
||||
songID: 439,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-09-15 0:44:48'),
|
||||
difficulties: 3,
|
||||
},
|
||||
{
|
||||
score: 79,
|
||||
songID: 234,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-09-13 13:53:16'),
|
||||
difficulties: 2,
|
||||
},
|
||||
{
|
||||
score: 0,
|
||||
songID: 369,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-30 22:54:34'),
|
||||
difficulties: 1,
|
||||
},
|
||||
{
|
||||
score: 25,
|
||||
songID: 223,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-09-13 1:09:11'),
|
||||
difficulties: 3,
|
||||
},
|
||||
{
|
||||
score: 55,
|
||||
songID: 716,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-12 19:43:23'),
|
||||
difficulties: 3,
|
||||
},
|
||||
{
|
||||
score: 100,
|
||||
songID: 62,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-11 15:33:40'),
|
||||
difficulties: 5,
|
||||
},
|
||||
{
|
||||
score: 74,
|
||||
songID: 271,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-08-25 23:14:51'),
|
||||
difficulties: 3,
|
||||
},
|
||||
{
|
||||
score: 22,
|
||||
songID: 265,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-17 15:01:38'),
|
||||
difficulties: 1,
|
||||
},
|
||||
{
|
||||
score: 79,
|
||||
songID: 552,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-28 20:13:14'),
|
||||
difficulties: 5,
|
||||
},
|
||||
{
|
||||
score: 50,
|
||||
songID: 603,
|
||||
userID: 18,
|
||||
playDate: new Date('2023-07-06 3:52:21'),
|
||||
difficulties: 5,
|
||||
},
|
||||
];
|
||||
|
||||
function xpToLevel(xp: number): number {
|
||||
@@ -128,6 +726,7 @@ const ProfileView = () => {
|
||||
const layout = useWindowDimensions();
|
||||
const navigation = useNavigation();
|
||||
const userQuery = useQuery(API.getUserInfo);
|
||||
// const scoresQuery = useQuery(API.getSongHistory(props.songId), { refetchOnWindowFocus: true });
|
||||
|
||||
if (!userQuery.data) {
|
||||
return <LoadingView />;
|
||||
@@ -138,36 +737,68 @@ const ProfileView = () => {
|
||||
const level = xpToLevel(userQuery.data.data.xp);
|
||||
|
||||
return (
|
||||
<Flex style={{ minHeight: layout.height, height: '100%', padding: 20}} >
|
||||
<Wrap style={{flexDirection: layout.width > 650 ? 'row' : 'column', alignItems: 'center', paddingBottom: 20, justifyContent: 'space-between'}}>
|
||||
<UserAvatar size={"2xl"}/>
|
||||
<Column style={{paddingLeft: layout.width > 650 ? 20 : 0, paddingTop: layout.width > 650 ? 0 : 20, flex: 1, width: '100%'}}>
|
||||
<Wrap style={{flexDirection: 'row', alignItems: 'center', paddingBottom: 20, justifyContent: 'space-between'}}>
|
||||
<Text fontSize={'xl'} style={{paddingRight: 'auto'}}>{userQuery.data.name}</Text>
|
||||
<Flex style={{ minHeight: layout.height, height: '100%', padding: 20 }}>
|
||||
<Wrap
|
||||
style={{
|
||||
flexDirection: layout.width > 650 ? 'row' : 'column',
|
||||
alignItems: 'center',
|
||||
paddingBottom: 20,
|
||||
justifyContent: 'space-between',
|
||||
}}
|
||||
>
|
||||
<UserAvatar size={layout.width > 650 ? 'xl' : '2xl'} />
|
||||
<Column
|
||||
style={{
|
||||
paddingLeft: layout.width > 650 ? 20 : 0,
|
||||
paddingTop: layout.width > 650 ? 0 : 20,
|
||||
flex: 1,
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<Wrap
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingBottom: 20,
|
||||
justifyContent: 'space-between',
|
||||
}}
|
||||
>
|
||||
<Text fontSize={'xl'} style={{ paddingRight: 'auto' }}>
|
||||
{userQuery.data.name}
|
||||
</Text>
|
||||
<ButtonBase
|
||||
title='Modifier profil'
|
||||
style={{width: 'fit-content'}}
|
||||
title="Modifier profil"
|
||||
style={{ width: 'fit-content' }}
|
||||
type={'filled'}
|
||||
onPress={async () => navigation.navigate('Settings')}
|
||||
/>
|
||||
</Wrap>
|
||||
<Text style={{ paddingBottom: 20 }}>Dernier entraînement il y a une semaine</Text>
|
||||
<Wrap style={{flexDirection: 'row', alignItems: 'center', paddingBottom: 20}}>
|
||||
<Text style={{paddingRight: 20}}>32 Completes</Text>
|
||||
<Text>42 En cours</Text>
|
||||
<Text style={{ paddingBottom: 10, fontWeight: 'bold' }}>
|
||||
Account created on {userQuery.data.data.createdAt.toLocaleDateString()}
|
||||
</Text>
|
||||
<Wrap style={{ flexDirection: 'row', alignItems: 'center', paddingBottom: 10 }}>
|
||||
<Text style={{ paddingRight: 20 }}>
|
||||
Your client ID is {userQuery.data.id}
|
||||
</Text>
|
||||
<Text>{userQuery.data.data.gamesPlayed} Games played</Text>
|
||||
</Wrap>
|
||||
</Column>
|
||||
</Wrap>
|
||||
<Row style={{alignItems: 'center', paddingBottom: 40}}>
|
||||
<Text style={{paddingRight: 20}}>{`${translate('level')} ${level}`}</Text>
|
||||
<Progress value={progessValue} w={'2/3'} maxW={'400'}/>
|
||||
<Row style={{ alignItems: 'center', paddingBottom: 20 }}>
|
||||
<Text style={{ paddingRight: 20 }}>{`${translate('level')} ${level}`}</Text>
|
||||
<Progress
|
||||
bgColor={'#rgba(16,16,20,0.5)'}
|
||||
value={progessValue}
|
||||
w={'2/3'}
|
||||
maxW={'400'}
|
||||
/>
|
||||
</Row>
|
||||
<ScoreGraph songHistory={
|
||||
{
|
||||
<ScoreGraph
|
||||
songHistory={{
|
||||
history: fakeData,
|
||||
best: 200
|
||||
}
|
||||
} />
|
||||
best: 200,
|
||||
}}
|
||||
/>
|
||||
<LinearGradient
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
|
||||
@@ -31,7 +31,7 @@ const hanldeSignin = async (
|
||||
const SigninView = () => {
|
||||
const dispatch = useDispatch();
|
||||
const navigation = useNavigation();
|
||||
const [formData, setFormData] = React.useState({
|
||||
const [formData, setFormData] = React.useState({
|
||||
username: {
|
||||
value: '',
|
||||
error: null as string | null,
|
||||
@@ -53,89 +53,91 @@ const SigninView = () => {
|
||||
};
|
||||
const toast = useToast();
|
||||
|
||||
const onSubmit= (username: string, password: string) => {
|
||||
return hanldeSignin(username, password, (accessToken) =>
|
||||
dispatch(setAccessToken(accessToken))
|
||||
);
|
||||
}
|
||||
const onSubmit = (username: string, password: string) => {
|
||||
return hanldeSignin(username, password, (accessToken) =>
|
||||
dispatch(setAccessToken(accessToken))
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<ScaffoldAuth
|
||||
title="Bienvenue !"
|
||||
description="Continuez avec Google ou entrez vos coordonnées."
|
||||
form={[
|
||||
<TextFormField
|
||||
error={formData.username.error}
|
||||
icon={User}
|
||||
placeholder="Username"
|
||||
autoComplete="username"
|
||||
value={formData.username.value}
|
||||
onChangeText={(t) => {
|
||||
let error: null | string = null;
|
||||
validationSchemas.username
|
||||
.validate(t)
|
||||
.catch((e) => (error = e.message))
|
||||
.finally(() => {
|
||||
setFormData({ ...formData, username: { value: t, error } });
|
||||
});
|
||||
}}
|
||||
isRequired
|
||||
/>,
|
||||
<TextFormField
|
||||
error={formData.password.error}
|
||||
icon={Lock1}
|
||||
placeholder="Password"
|
||||
autoComplete="password"
|
||||
value={formData.password.value}
|
||||
onChangeText={(t) => {
|
||||
let error: null | string = null;
|
||||
validationSchemas.password
|
||||
.validate(t)
|
||||
.catch((e) => (error = e.message))
|
||||
.finally(() => {
|
||||
setFormData({ ...formData, password: { value: t, error } });
|
||||
});
|
||||
}}
|
||||
isRequired
|
||||
/>,
|
||||
<LinkBase onPress={() => console.log('Link clicked!')}>
|
||||
{translate('forgottenPassword')}
|
||||
</LinkBase>,
|
||||
]}
|
||||
submitButton={
|
||||
<ButtonBase
|
||||
style={{width: '100%'}}
|
||||
title="Signin"
|
||||
isDisabled={
|
||||
formData.password.error !== null ||
|
||||
formData.username.error !== null ||
|
||||
formData.username.value === '' ||
|
||||
formData.password.value === ''
|
||||
}
|
||||
onPress={async () => {
|
||||
try {
|
||||
const resp = await onSubmit(
|
||||
formData.username.value,
|
||||
formData.password.value
|
||||
);
|
||||
toast.show({ description: resp, colorScheme: 'secondary' });
|
||||
} catch (e) {
|
||||
toast.show({
|
||||
description: e as string,
|
||||
colorScheme: 'red',
|
||||
avoidKeyboard: true,
|
||||
});
|
||||
}
|
||||
}}
|
||||
/>
|
||||
}
|
||||
link={{
|
||||
text: "Inscrivez-vous gratuitement",
|
||||
description: "Vous n'avez pas de compte ? ",
|
||||
onPress: () => navigation.navigate('Signup')
|
||||
}}
|
||||
/>
|
||||
);
|
||||
return (
|
||||
<ScaffoldAuth
|
||||
title="Bienvenue !"
|
||||
description="Continuez avec Google ou entrez vos coordonnées."
|
||||
form={[
|
||||
<TextFormField
|
||||
key={'signin-form-1'}
|
||||
error={formData.username.error}
|
||||
icon={User}
|
||||
placeholder="Username"
|
||||
autoComplete="username"
|
||||
value={formData.username.value}
|
||||
onChangeText={(t) => {
|
||||
let error: null | string = null;
|
||||
validationSchemas.username
|
||||
.validate(t)
|
||||
.catch((e) => (error = e.message))
|
||||
.finally(() => {
|
||||
setFormData({ ...formData, username: { value: t, error } });
|
||||
});
|
||||
}}
|
||||
isRequired
|
||||
/>,
|
||||
<TextFormField
|
||||
key={'signin-form-2'}
|
||||
error={formData.password.error}
|
||||
icon={Lock1}
|
||||
placeholder="Password"
|
||||
autoComplete="password"
|
||||
value={formData.password.value}
|
||||
onChangeText={(t) => {
|
||||
let error: null | string = null;
|
||||
validationSchemas.password
|
||||
.validate(t)
|
||||
.catch((e) => (error = e.message))
|
||||
.finally(() => {
|
||||
setFormData({ ...formData, password: { value: t, error } });
|
||||
});
|
||||
}}
|
||||
isRequired
|
||||
/>,
|
||||
<LinkBase key={'signin-link'} onPress={() => console.log('Link clicked!')}>
|
||||
{translate('forgottenPassword')}
|
||||
</LinkBase>,
|
||||
]}
|
||||
submitButton={
|
||||
<ButtonBase
|
||||
style={{ width: '100%' }}
|
||||
title="Signin"
|
||||
isDisabled={
|
||||
formData.password.error !== null ||
|
||||
formData.username.error !== null ||
|
||||
formData.username.value === '' ||
|
||||
formData.password.value === ''
|
||||
}
|
||||
onPress={async () => {
|
||||
try {
|
||||
const resp = await onSubmit(
|
||||
formData.username.value,
|
||||
formData.password.value
|
||||
);
|
||||
toast.show({ description: resp, colorScheme: 'secondary' });
|
||||
} catch (e) {
|
||||
toast.show({
|
||||
description: e as string,
|
||||
colorScheme: 'red',
|
||||
avoidKeyboard: true,
|
||||
});
|
||||
}
|
||||
}}
|
||||
/>
|
||||
}
|
||||
link={{
|
||||
text: 'Inscrivez-vous gratuitement',
|
||||
description: "Vous n'avez pas de compte ? ",
|
||||
onPress: () => navigation.navigate('Signup'),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default SigninView;
|
||||
export default SigninView;
|
||||
|
||||
@@ -29,9 +29,9 @@ const handleSignup = async (
|
||||
};
|
||||
|
||||
const SignupView = () => {
|
||||
const dispatch = useDispatch();
|
||||
const dispatch = useDispatch();
|
||||
const navigation = useNavigation();
|
||||
const [formData, setFormData] = React.useState({
|
||||
const [formData, setFormData] = React.useState({
|
||||
username: {
|
||||
value: '',
|
||||
error: null as string | null,
|
||||
@@ -68,133 +68,137 @@ const SignupView = () => {
|
||||
};
|
||||
const toast = useToast();
|
||||
|
||||
const onSubmit= (username: string, email: string, password: string) => {
|
||||
return handleSignup(username, password, email, (accessToken) =>
|
||||
dispatch(setAccessToken(accessToken))
|
||||
)
|
||||
}
|
||||
const onSubmit = (username: string, email: string, password: string) => {
|
||||
return handleSignup(username, password, email, (accessToken) =>
|
||||
dispatch(setAccessToken(accessToken))
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<ScaffoldAuth
|
||||
title="Créer un compte"
|
||||
description="Apprendre le piano gratuitement et de manière ludique"
|
||||
form={[
|
||||
<TextFormField
|
||||
error={formData.username.error}
|
||||
icon={User}
|
||||
placeholder="Username"
|
||||
autoComplete="username"
|
||||
value={formData.username.value}
|
||||
onChangeText={(t) => {
|
||||
let error: null | string = null;
|
||||
validationSchemas.username
|
||||
.validate(t)
|
||||
.catch((e) => (error = e.message))
|
||||
.finally(() => {
|
||||
setFormData({ ...formData, username: { value: t, error } });
|
||||
});
|
||||
}}
|
||||
isRequired
|
||||
/>,
|
||||
<TextFormField
|
||||
error={formData.email.error}
|
||||
icon={Sms}
|
||||
placeholder="Email"
|
||||
autoComplete="email"
|
||||
value={formData.email.value}
|
||||
onChangeText={(t) => {
|
||||
let error: null | string = null;
|
||||
validationSchemas.email
|
||||
.validate(t)
|
||||
.catch((e) => (error = e.message))
|
||||
.finally(() => {
|
||||
setFormData({ ...formData, email: { value: t, error } });
|
||||
});
|
||||
}}
|
||||
isRequired
|
||||
/>,
|
||||
<TextFormField
|
||||
isRequired
|
||||
isSecret
|
||||
error={formData.password.error}
|
||||
icon={Lock1}
|
||||
placeholder="Password"
|
||||
autoComplete="password-new"
|
||||
value={formData.password.value}
|
||||
onChangeText={(t) => {
|
||||
let error: null | string = null;
|
||||
validationSchemas.password
|
||||
.validate(t)
|
||||
.catch((e) => (error = e.message))
|
||||
.finally(() => {
|
||||
setFormData({ ...formData, password: { value: t, error } });
|
||||
});
|
||||
}}
|
||||
/>,
|
||||
<TextFormField
|
||||
isRequired
|
||||
isSecret
|
||||
error={formData.repeatPassword.error}
|
||||
icon={Lock1}
|
||||
placeholder="Repeat password"
|
||||
autoComplete="password-new"
|
||||
value={formData.repeatPassword.value}
|
||||
onChangeText={(t) => {
|
||||
let error: null | string = null;
|
||||
validationSchemas.password
|
||||
.validate(t)
|
||||
.catch((e) => (error = e.message))
|
||||
.finally(() => {
|
||||
if (!error && t !== formData.password.value) {
|
||||
error = translate('passwordsDontMatch');
|
||||
}
|
||||
setFormData({
|
||||
...formData,
|
||||
repeatPassword: { value: t, error },
|
||||
});
|
||||
});
|
||||
}}
|
||||
/>
|
||||
]}
|
||||
submitButton={
|
||||
<ButtonBase
|
||||
style={{width: '100%'}}
|
||||
title="Signin"
|
||||
isDisabled={
|
||||
formData.password.error !== null ||
|
||||
formData.username.error !== null ||
|
||||
formData.repeatPassword.error !== null ||
|
||||
formData.email.error !== null ||
|
||||
formData.username.value === '' ||
|
||||
formData.password.value === '' ||
|
||||
formData.repeatPassword.value === '' ||
|
||||
formData.repeatPassword.value === ''
|
||||
}
|
||||
onPress={async () => {
|
||||
try {
|
||||
const resp = await onSubmit(
|
||||
formData.username.value,
|
||||
formData.password.value,
|
||||
formData.email.value
|
||||
);
|
||||
toast.show({ description: resp, colorScheme: 'secondary' });
|
||||
} catch (e) {
|
||||
toast.show({
|
||||
description: e as string,
|
||||
colorScheme: 'red',
|
||||
avoidKeyboard: true,
|
||||
});
|
||||
}
|
||||
}}
|
||||
/>
|
||||
}
|
||||
link={{
|
||||
text: "S'identifier",
|
||||
description: "Vous avez déjà un compte ? ",
|
||||
onPress: () => navigation.navigate('Login')
|
||||
}}
|
||||
/>
|
||||
);
|
||||
return (
|
||||
<ScaffoldAuth
|
||||
title="Créer un compte"
|
||||
description="Apprendre le piano gratuitement et de manière ludique"
|
||||
form={[
|
||||
<TextFormField
|
||||
key={'signup-form-1'}
|
||||
error={formData.username.error}
|
||||
icon={User}
|
||||
placeholder="Username"
|
||||
autoComplete="username"
|
||||
value={formData.username.value}
|
||||
onChangeText={(t) => {
|
||||
let error: null | string = null;
|
||||
validationSchemas.username
|
||||
.validate(t)
|
||||
.catch((e) => (error = e.message))
|
||||
.finally(() => {
|
||||
setFormData({ ...formData, username: { value: t, error } });
|
||||
});
|
||||
}}
|
||||
isRequired
|
||||
/>,
|
||||
<TextFormField
|
||||
key={'signup-form-2'}
|
||||
error={formData.email.error}
|
||||
icon={Sms}
|
||||
placeholder="Email"
|
||||
autoComplete="email"
|
||||
value={formData.email.value}
|
||||
onChangeText={(t) => {
|
||||
let error: null | string = null;
|
||||
validationSchemas.email
|
||||
.validate(t)
|
||||
.catch((e) => (error = e.message))
|
||||
.finally(() => {
|
||||
setFormData({ ...formData, email: { value: t, error } });
|
||||
});
|
||||
}}
|
||||
isRequired
|
||||
/>,
|
||||
<TextFormField
|
||||
key={'signup-form-3'}
|
||||
isRequired
|
||||
isSecret
|
||||
error={formData.password.error}
|
||||
icon={Lock1}
|
||||
placeholder="Password"
|
||||
autoComplete="password-new"
|
||||
value={formData.password.value}
|
||||
onChangeText={(t) => {
|
||||
let error: null | string = null;
|
||||
validationSchemas.password
|
||||
.validate(t)
|
||||
.catch((e) => (error = e.message))
|
||||
.finally(() => {
|
||||
setFormData({ ...formData, password: { value: t, error } });
|
||||
});
|
||||
}}
|
||||
/>,
|
||||
<TextFormField
|
||||
key={'signup-form-4'}
|
||||
isRequired
|
||||
isSecret
|
||||
error={formData.repeatPassword.error}
|
||||
icon={Lock1}
|
||||
placeholder="Repeat password"
|
||||
autoComplete="password-new"
|
||||
value={formData.repeatPassword.value}
|
||||
onChangeText={(t) => {
|
||||
let error: null | string = null;
|
||||
validationSchemas.password
|
||||
.validate(t)
|
||||
.catch((e) => (error = e.message))
|
||||
.finally(() => {
|
||||
if (!error && t !== formData.password.value) {
|
||||
error = translate('passwordsDontMatch');
|
||||
}
|
||||
setFormData({
|
||||
...formData,
|
||||
repeatPassword: { value: t, error },
|
||||
});
|
||||
});
|
||||
}}
|
||||
/>,
|
||||
]}
|
||||
submitButton={
|
||||
<ButtonBase
|
||||
style={{ width: '100%' }}
|
||||
title="Signin"
|
||||
isDisabled={
|
||||
formData.password.error !== null ||
|
||||
formData.username.error !== null ||
|
||||
formData.repeatPassword.error !== null ||
|
||||
formData.email.error !== null ||
|
||||
formData.username.value === '' ||
|
||||
formData.password.value === '' ||
|
||||
formData.repeatPassword.value === '' ||
|
||||
formData.repeatPassword.value === ''
|
||||
}
|
||||
onPress={async () => {
|
||||
try {
|
||||
const resp = await onSubmit(
|
||||
formData.username.value,
|
||||
formData.password.value,
|
||||
formData.email.value
|
||||
);
|
||||
toast.show({ description: resp, colorScheme: 'secondary' });
|
||||
} catch (e) {
|
||||
toast.show({
|
||||
description: e as string,
|
||||
colorScheme: 'red',
|
||||
avoidKeyboard: true,
|
||||
});
|
||||
}
|
||||
}}
|
||||
/>
|
||||
}
|
||||
link={{
|
||||
text: "S'identifier",
|
||||
description: 'Vous avez déjà un compte ? ',
|
||||
onPress: () => navigation.navigate('Login'),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default SignupView;
|
||||
export default SignupView;
|
||||
|
||||
Reference in New Issue
Block a user