Front: Merge
This commit is contained in:
18
front/API.ts
18
front/API.ts
@@ -13,6 +13,7 @@ import { en } from "./i18n/Translations";
|
||||
import { QueryClient } from "react-query";
|
||||
import UserSettings from "./models/UserSettings";
|
||||
import { PartialDeep } from "type-fest";
|
||||
import SearchHistory from "./models/SearchHistory";
|
||||
|
||||
type AuthenticationInput = { username: string; password: string };
|
||||
type RegistrationInput = AuthenticationInput & { email: string };
|
||||
@@ -364,15 +365,16 @@ export default class API {
|
||||
* Retrieve the authenticated user's search history
|
||||
* @param lessonId the id to find the lesson
|
||||
*/
|
||||
public static async getSearchHistory(): Promise<Song[]> {
|
||||
const queryClient = new QueryClient();
|
||||
let songs = await queryClient.fetchQuery(
|
||||
["API", "allsongs"],
|
||||
API.getAllSongs
|
||||
);
|
||||
const shuffled = [...songs].sort(() => 0.5 - Math.random());
|
||||
public static async getSearchHistory(): Promise<SearchHistory[]> {
|
||||
const tmp = await this.fetch({
|
||||
route: "/history/search",
|
||||
});
|
||||
|
||||
return shuffled.slice(0, 2);
|
||||
return tmp.map((value: any) => ({
|
||||
query: value.query,
|
||||
userID: value.userId,
|
||||
id: value.id,
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,6 +3,7 @@ import { NavigationProp, ParamListBase, useNavigation as navigationHook } from "
|
||||
import React, { useEffect } from 'react';
|
||||
import { DarkTheme, DefaultTheme, NavigationContainer } from '@react-navigation/native';
|
||||
import { RootState, useSelector } from './state/Store';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { Translate, translate } from './i18n/i18n';
|
||||
import SongLobbyView from './views/SongLobbyView';
|
||||
import AuthenticationView from './views/AuthenticationView';
|
||||
@@ -18,7 +19,6 @@ import { LoadingView } from './components/Loading';
|
||||
import ProfileView from './views/ProfileView';
|
||||
import useColorScheme from './hooks/colorScheme';
|
||||
import { Button, Center, VStack } from 'native-base';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { unsetAccessToken } from './state/UserSlice';
|
||||
import TextButton from './components/TextButton';
|
||||
|
||||
@@ -86,10 +86,16 @@ const ProfileErrorView = (props: { onTryAgain: () => any }) => {
|
||||
}
|
||||
|
||||
export const Router = () => {
|
||||
const dispatch = useDispatch();
|
||||
const accessToken = useSelector((state: RootState) => state.user.accessToken);
|
||||
const userProfile = useQuery(['user', 'me', accessToken], () => API.getUserInfo(), {
|
||||
retry: 1,
|
||||
refetchOnWindowFocus: false
|
||||
refetchOnWindowFocus: false,
|
||||
onError: (err) => {
|
||||
if (err.status === 401) {
|
||||
dispatch(unsetAccessToken());
|
||||
}
|
||||
},
|
||||
});
|
||||
const colorScheme = useColorScheme();
|
||||
|
||||
|
||||
@@ -162,6 +162,9 @@ export const en = {
|
||||
|
||||
Attention: 'Attention',
|
||||
YouAreCurrentlyConnectedWithAGuestAccountWarning: "You are currently connected with a guest account. Disconneting will result in your data being lost. If you want to save your progress, you need to create an account.",
|
||||
|
||||
recentSearches: 'Recent searches',
|
||||
noRecentSearches: 'No recent searches',
|
||||
};
|
||||
|
||||
export const fr: typeof en = {
|
||||
@@ -323,6 +326,9 @@ export const fr: typeof en = {
|
||||
|
||||
Attention: 'Attention',
|
||||
YouAreCurrentlyConnectedWithAGuestAccountWarning: 'Vous êtes actuellement connecté en tant qu\'invité. La déconnexion résultera en une perte de données. Vous pouvez créer un compte pour sauvegarder vos données.',
|
||||
|
||||
recentSearches: 'Recherches récentes',
|
||||
noRecentSearches: 'Aucune recherche récente',
|
||||
};
|
||||
|
||||
export const sp: typeof en = {
|
||||
@@ -489,4 +495,7 @@ export const sp: typeof en = {
|
||||
|
||||
Attention: 'Atención',
|
||||
YouAreCurrentlyConnectedWithAGuestAccountWarning: 'Actualmente estás conectado como invitado. La desconexión resultará en la pérdida de datos. Puedes crear una cuenta para guardar tus datos.',
|
||||
|
||||
recentSearches: 'Búsquedas recientes',
|
||||
noRecentSearches: 'No hay búsquedas recientes',
|
||||
};
|
||||
7
front/models/SearchHistory.ts
Normal file
7
front/models/SearchHistory.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
interface SearchHistory {
|
||||
query: string;
|
||||
userID: number;
|
||||
id: number;
|
||||
}
|
||||
|
||||
export default SearchHistory;
|
||||
@@ -2,17 +2,34 @@ import React from "react";
|
||||
import { useQueries, useQuery } from "react-query";
|
||||
import API from "../API";
|
||||
import { LoadingView } from "../components/Loading";
|
||||
import { Center, Box, ScrollView, Flex, useBreakpointValue, Stack, Heading, Container, VStack, HStack } from 'native-base';
|
||||
import {
|
||||
Center,
|
||||
Box,
|
||||
ScrollView,
|
||||
Flex,
|
||||
useBreakpointValue,
|
||||
Stack,
|
||||
Heading,
|
||||
Container,
|
||||
VStack,
|
||||
HStack,
|
||||
Column,
|
||||
Button,
|
||||
Text,
|
||||
useTheme
|
||||
} from "native-base";
|
||||
|
||||
import { useNavigation } from "../Navigation";
|
||||
import SongCardGrid from '../components/SongCardGrid';
|
||||
import CompetenciesTable from '../components/CompetenciesTable'
|
||||
import SongCardGrid from "../components/SongCardGrid";
|
||||
import CompetenciesTable from "../components/CompetenciesTable";
|
||||
import ProgressBar from "../components/ProgressBar";
|
||||
import Translate from "../components/Translate";
|
||||
import TextButton from "../components/TextButton";
|
||||
import Song from "../models/Song";
|
||||
import { FontAwesome5 } from "@expo/vector-icons";
|
||||
|
||||
const HomeView = () => {
|
||||
const theme = useTheme();
|
||||
const navigation = useNavigation();
|
||||
const screenSize = useBreakpointValue({ base: 'small', md: "big"});
|
||||
const userQuery = useQuery(['user'], () => API.getUserInfo());
|
||||
@@ -106,17 +123,39 @@ const HomeView = () => {
|
||||
/>
|
||||
</HStack>
|
||||
<Box style={{ width: '100%' }}>
|
||||
<SongCardGrid
|
||||
heading={<Translate translationKey='lastSearched'/>}
|
||||
songs={searchHistoryQuery.data?.filter((song) => artistsQueries.find((artistQuery) => artistQuery.data?.id === song.artistId))
|
||||
.map((song) => ({
|
||||
albumCover: song.cover,
|
||||
songTitle: song.name,
|
||||
songId: song.id,
|
||||
artistName: artistsQueries.find((artistQuery) => artistQuery.data?.id === song.artistId)!.data!.name
|
||||
})) ?? []
|
||||
<Heading><Translate translationKey='recentSearches'/></Heading>
|
||||
<Flex padding={3} style={{
|
||||
width: '100%',
|
||||
alignItems: 'flex-start',
|
||||
alignContent: 'flex-start',
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
}}>
|
||||
{
|
||||
searchHistoryQuery.data?.length === 0 && <Translate translationKey='noRecentSearches'/>
|
||||
}
|
||||
/>
|
||||
{
|
||||
[...(new Set(searchHistoryQuery.data.map((x) => x.query)))].reverse().slice(0, 5).map((query) => (
|
||||
<Button
|
||||
leftIcon={
|
||||
<FontAwesome5 name="search" size={16} />
|
||||
}
|
||||
style={{
|
||||
margin: 2,
|
||||
}}
|
||||
key={ query }
|
||||
variant="solid"
|
||||
size="xs"
|
||||
colorScheme="primary"
|
||||
onPress={() => navigation.navigate('Search', { query: query })}
|
||||
>
|
||||
<Text fontSize={"xs"} isTruncated maxW={"150px"}>
|
||||
{ query }
|
||||
</Text>
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
</Flex>
|
||||
</Box>
|
||||
</VStack>
|
||||
</Stack>
|
||||
|
||||
Reference in New Issue
Block a user