switch to async storage for faster loading
All checks were successful
deploy / deploy (push) Successful in 1m55s
All checks were successful
deploy / deploy (push) Successful in 1m55s
This commit is contained in:
parent
70ed248be7
commit
a0aca8c9b1
6
package-lock.json
generated
6
package-lock.json
generated
@ -15,6 +15,7 @@
|
|||||||
"clsx": "^2.0.0",
|
"clsx": "^2.0.0",
|
||||||
"date-fns": "^2.30.0",
|
"date-fns": "^2.30.0",
|
||||||
"encoding": "^0.1.13",
|
"encoding": "^0.1.13",
|
||||||
|
"idb-keyval": "^6.2.1",
|
||||||
"next": "13.5.6",
|
"next": "13.5.6",
|
||||||
"next-build-id": "^3.0.0",
|
"next-build-id": "^3.0.0",
|
||||||
"node-fetch-cache": "^3.1.3",
|
"node-fetch-cache": "^3.1.3",
|
||||||
@ -3010,6 +3011,11 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/idb-keyval": {
|
||||||
|
"version": "6.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz",
|
||||||
|
"integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg=="
|
||||||
|
},
|
||||||
"node_modules/ieee754": {
|
"node_modules/ieee754": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
"clsx": "^2.0.0",
|
"clsx": "^2.0.0",
|
||||||
"date-fns": "^2.30.0",
|
"date-fns": "^2.30.0",
|
||||||
"encoding": "^0.1.13",
|
"encoding": "^0.1.13",
|
||||||
|
"idb-keyval": "^6.2.1",
|
||||||
"next": "13.5.6",
|
"next": "13.5.6",
|
||||||
"next-build-id": "^3.0.0",
|
"next-build-id": "^3.0.0",
|
||||||
"node-fetch-cache": "^3.1.3",
|
"node-fetch-cache": "^3.1.3",
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { AppProvider } from "@/components/AppProvider";
|
import AppProvider from "@/components/AppProvider";
|
||||||
import { ssrSettings } from "@/ssrSettings";
|
import { ssrSettings } from "@/ssrSettings";
|
||||||
import { Metadata } from "next";
|
import { Metadata } from "next";
|
||||||
import { Inter } from "next/font/google";
|
import { Inter } from "next/font/google";
|
||||||
|
@ -1,18 +1,48 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useScoresaberScoresStore } from "@/store/scoresaberScoresStore";
|
import { useScoresaberScoresStore } from "@/store/scoresaberScoresStore";
|
||||||
|
import { useSettingsStore } from "@/store/settingsStore";
|
||||||
type AppProviderProps = {
|
import React from "react";
|
||||||
children: React.ReactNode;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function AppProvider({ children }: AppProviderProps) {
|
|
||||||
return <>{children}</>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const UPDATE_INTERVAL = 1000 * 60 * 15; // 15 minutes
|
const UPDATE_INTERVAL = 1000 * 60 * 15; // 15 minutes
|
||||||
|
|
||||||
useScoresaberScoresStore.getState().updatePlayerScores();
|
export default class AppProvider extends React.Component {
|
||||||
|
_state = {
|
||||||
|
mounted: false, // Whether the component has mounted
|
||||||
|
// Whether the data from the async storage has been loaded
|
||||||
|
dataLoaded: {
|
||||||
|
scores: false,
|
||||||
|
settings: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
async componentDidMount(): Promise<void> {
|
||||||
|
if (this._state.mounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._state.mounted = true;
|
||||||
|
|
||||||
|
// Load data from async storage
|
||||||
|
await useSettingsStore.persist.rehydrate();
|
||||||
|
await useScoresaberScoresStore.persist.rehydrate();
|
||||||
|
|
||||||
|
await useSettingsStore.getState().refreshProfiles();
|
||||||
|
setInterval(() => {
|
||||||
|
useSettingsStore.getState().refreshProfiles();
|
||||||
|
}, UPDATE_INTERVAL);
|
||||||
|
|
||||||
|
await useScoresaberScoresStore.getState().updatePlayerScores();
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
useScoresaberScoresStore.getState().updatePlayerScores();
|
useScoresaberScoresStore.getState().updatePlayerScores();
|
||||||
}, UPDATE_INTERVAL);
|
}, UPDATE_INTERVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(props: any) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
render(): React.ReactNode {
|
||||||
|
const props: any = this.props;
|
||||||
|
|
||||||
|
return <>{props.children}</>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -8,6 +8,7 @@ import { ScoresaberPlayer } from "@/schemas/scoresaber/player";
|
|||||||
import { useSettingsStore } from "@/store/settingsStore";
|
import { useSettingsStore } from "@/store/settingsStore";
|
||||||
import { SortType, SortTypes } from "@/types/SortTypes";
|
import { SortType, SortTypes } from "@/types/SortTypes";
|
||||||
import { ScoreSaberAPI } from "@/utils/scoresaber/api";
|
import { ScoreSaberAPI } from "@/utils/scoresaber/api";
|
||||||
|
import useStore from "@/utils/useStore";
|
||||||
import dynamic from "next/dynamic";
|
import dynamic from "next/dynamic";
|
||||||
import { useSearchParams } from "next/navigation";
|
import { useSearchParams } from "next/navigation";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
@ -27,6 +28,7 @@ type PlayerPageProps = {
|
|||||||
const DEFAULT_SORT_TYPE = SortTypes.top;
|
const DEFAULT_SORT_TYPE = SortTypes.top;
|
||||||
|
|
||||||
export default function PlayerPage({ id }: PlayerPageProps) {
|
export default function PlayerPage({ id }: PlayerPageProps) {
|
||||||
|
const settingsStore = useStore(useSettingsStore, (store) => store);
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
|
|
||||||
const [mounted, setMounted] = useState(false);
|
const [mounted, setMounted] = useState(false);
|
||||||
@ -49,8 +51,7 @@ export default function PlayerPage({ id }: PlayerPageProps) {
|
|||||||
let sortType: SortType;
|
let sortType: SortType;
|
||||||
const sortTypeString = searchParams.get("sort");
|
const sortTypeString = searchParams.get("sort");
|
||||||
if (sortTypeString == null) {
|
if (sortTypeString == null) {
|
||||||
sortType =
|
sortType = settingsStore?.lastUsedSortType || DEFAULT_SORT_TYPE;
|
||||||
useSettingsStore.getState().lastUsedSortType || DEFAULT_SORT_TYPE;
|
|
||||||
} else {
|
} else {
|
||||||
sortType = SortTypes[sortTypeString] || DEFAULT_SORT_TYPE;
|
sortType = SortTypes[sortTypeString] || DEFAULT_SORT_TYPE;
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ import { ScoresaberPlayerScore } from "@/schemas/scoresaber/playerScore";
|
|||||||
import { useSettingsStore } from "@/store/settingsStore";
|
import { useSettingsStore } from "@/store/settingsStore";
|
||||||
import { SortType, SortTypes } from "@/types/SortTypes";
|
import { SortType, SortTypes } from "@/types/SortTypes";
|
||||||
import { ScoreSaberAPI } from "@/utils/scoresaber/api";
|
import { ScoreSaberAPI } from "@/utils/scoresaber/api";
|
||||||
|
import useStore from "@/utils/useStore";
|
||||||
import dynamic from "next/dynamic";
|
import dynamic from "next/dynamic";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
@ -27,6 +28,7 @@ type ScoresProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function Scores({ playerData, page, sortType }: ScoresProps) {
|
export default function Scores({ playerData, page, sortType }: ScoresProps) {
|
||||||
|
const settingsStore = useStore(useSettingsStore, (store) => store);
|
||||||
const playerId = playerData.id;
|
const playerId = playerData.id;
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -61,9 +63,7 @@ export default function Scores({ playerData, page, sortType }: ScoresProps) {
|
|||||||
page: page,
|
page: page,
|
||||||
sortType: sortType,
|
sortType: sortType,
|
||||||
});
|
});
|
||||||
useSettingsStore.setState({
|
settingsStore?.setLastUsedSortType(sortType);
|
||||||
lastUsedSortType: sortType,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (page > 1) {
|
if (page > 1) {
|
||||||
router.push(
|
router.push(
|
||||||
@ -80,7 +80,7 @@ export default function Scores({ playerData, page, sortType }: ScoresProps) {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
[playerId, router, scores],
|
[playerId, router, scores, settingsStore],
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
19
src/store/IndexedDBStorage.ts
Normal file
19
src/store/IndexedDBStorage.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { del, get, set } from "idb-keyval";
|
||||||
|
import { StateStorage } from "zustand/middleware";
|
||||||
|
|
||||||
|
export const IDBStorage: StateStorage = {
|
||||||
|
getItem: async (name: string): Promise<string | null> => {
|
||||||
|
//console.log(name, "has been retrieved");
|
||||||
|
return (await get(name)) || null;
|
||||||
|
},
|
||||||
|
setItem: async (name: string, value: string): Promise<void> => {
|
||||||
|
//console.log(name, "with value", value, "has been saved");
|
||||||
|
await set(name, value);
|
||||||
|
},
|
||||||
|
removeItem: async (name: string): Promise<void> => {
|
||||||
|
//console.log(name, "has been deleted");
|
||||||
|
await del(name);
|
||||||
|
},
|
||||||
|
};
|
@ -6,13 +6,12 @@ import { ScoreSaberAPI } from "@/utils/scoresaber/api";
|
|||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
import { createJSONStorage, persist } from "zustand/middleware";
|
import { createJSONStorage, persist } from "zustand/middleware";
|
||||||
|
import { IDBStorage } from "./IndexedDBStorage";
|
||||||
import { useSettingsStore } from "./settingsStore";
|
import { useSettingsStore } from "./settingsStore";
|
||||||
|
|
||||||
type Player = {
|
type Player = {
|
||||||
id: string;
|
id: string;
|
||||||
scores: {
|
scores: ScoresaberSmallerPlayerScore[];
|
||||||
scoresaber: ScoresaberSmallerPlayerScore[];
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
interface ScoreSaberScoresStore {
|
interface ScoreSaberScoresStore {
|
||||||
@ -60,14 +59,14 @@ interface ScoreSaberScoresStore {
|
|||||||
/**
|
/**
|
||||||
* Refreshes the player scores and adds any new scores to the local database
|
* Refreshes the player scores and adds any new scores to the local database
|
||||||
*/
|
*/
|
||||||
updatePlayerScores: () => void;
|
updatePlayerScores: () => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const UPDATE_INTERVAL = 1000 * 60 * 30; // 30 minutes
|
const UPDATE_INTERVAL = 1000 * 60 * 30; // 30 minutes
|
||||||
|
|
||||||
export const useScoresaberScoresStore = create<ScoreSaberScoresStore>()(
|
export const useScoresaberScoresStore = create<ScoreSaberScoresStore>()(
|
||||||
persist(
|
persist(
|
||||||
(set) => ({
|
(set, get) => ({
|
||||||
lastUpdated: 0,
|
lastUpdated: 0,
|
||||||
players: [],
|
players: [],
|
||||||
|
|
||||||
@ -76,12 +75,12 @@ export const useScoresaberScoresStore = create<ScoreSaberScoresStore>()(
|
|||||||
},
|
},
|
||||||
|
|
||||||
exists: (playerId: string) => {
|
exists: (playerId: string) => {
|
||||||
const players: Player[] = useScoresaberScoresStore.getState().players;
|
const players: Player[] = get().players;
|
||||||
return players.some((player) => player.id == playerId);
|
return players.some((player) => player.id == playerId);
|
||||||
},
|
},
|
||||||
|
|
||||||
get: (playerId: string) => {
|
get: (playerId: string) => {
|
||||||
const players: Player[] = useScoresaberScoresStore.getState().players;
|
const players: Player[] = get().players;
|
||||||
return players.find((player) => player.id == playerId);
|
return players.find((player) => player.id == playerId);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -89,10 +88,10 @@ export const useScoresaberScoresStore = create<ScoreSaberScoresStore>()(
|
|||||||
playerId: string,
|
playerId: string,
|
||||||
callback?: (page: number, totalPages: number) => void,
|
callback?: (page: number, totalPages: number) => void,
|
||||||
) => {
|
) => {
|
||||||
const players = useScoresaberScoresStore.getState().players;
|
const players: Player[] = get().players;
|
||||||
|
|
||||||
// Check if the player already exists
|
// Check if the player already exists
|
||||||
if (useScoresaberScoresStore.getState().exists(playerId)) {
|
if (get().exists(playerId)) {
|
||||||
return {
|
return {
|
||||||
error: true,
|
error: true,
|
||||||
message: "Player already exists",
|
message: "Player already exists",
|
||||||
@ -146,13 +145,12 @@ export const useScoresaberScoresStore = create<ScoreSaberScoresStore>()(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove scores that are already in the database
|
// Remove scores that are already in the database
|
||||||
const player = useScoresaberScoresStore.getState().get(playerId);
|
const player = get().get(playerId);
|
||||||
if (player) {
|
if (player) {
|
||||||
scores = scores.filter(
|
scores = scores.filter(
|
||||||
(score) =>
|
(score) =>
|
||||||
player.scores.scoresaber.findIndex(
|
player.scores.findIndex((s) => s.score.id == score.score.id) ==
|
||||||
(s) => s.score.id == score.score.id,
|
-1,
|
||||||
) == -1,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,9 +159,7 @@ export const useScoresaberScoresStore = create<ScoreSaberScoresStore>()(
|
|||||||
...players,
|
...players,
|
||||||
{
|
{
|
||||||
id: playerId,
|
id: playerId,
|
||||||
scores: {
|
scores: scores,
|
||||||
scoresaber: scores,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
@ -174,7 +170,7 @@ export const useScoresaberScoresStore = create<ScoreSaberScoresStore>()(
|
|||||||
},
|
},
|
||||||
|
|
||||||
updatePlayerScores: async () => {
|
updatePlayerScores: async () => {
|
||||||
const players = useScoresaberScoresStore.getState().players;
|
const players = get().players;
|
||||||
const friends = useSettingsStore.getState().friends;
|
const friends = useSettingsStore.getState().friends;
|
||||||
|
|
||||||
let allPlayers = new Array<ScoresaberPlayer>();
|
let allPlayers = new Array<ScoresaberPlayer>();
|
||||||
@ -188,7 +184,11 @@ export const useScoresaberScoresStore = create<ScoreSaberScoresStore>()(
|
|||||||
|
|
||||||
// add local player and friends if they don't exist
|
// add local player and friends if they don't exist
|
||||||
for (const player of allPlayers) {
|
for (const player of allPlayers) {
|
||||||
if (useScoresaberScoresStore.getState().get(player.id) == undefined) {
|
if (get().lastUpdated == 0) {
|
||||||
|
set({ lastUpdated: Date.now() });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (get().get(player.id) == undefined) {
|
||||||
toast.info(
|
toast.info(
|
||||||
`${
|
`${
|
||||||
player.id == localPlayer?.id
|
player.id == localPlayer?.id
|
||||||
@ -196,7 +196,7 @@ export const useScoresaberScoresStore = create<ScoreSaberScoresStore>()(
|
|||||||
: `Friend ${player.name} was`
|
: `Friend ${player.name} was`
|
||||||
} missing from the ScoreSaber scores database, adding...`,
|
} missing from the ScoreSaber scores database, adding...`,
|
||||||
);
|
);
|
||||||
await useScoresaberScoresStore.getState().addPlayer(player.id);
|
await get().addPlayer(player.id);
|
||||||
toast.success(
|
toast.success(
|
||||||
`${
|
`${
|
||||||
player.id == useSettingsStore.getState().player?.id
|
player.id == useSettingsStore.getState().player?.id
|
||||||
@ -209,18 +209,14 @@ export const useScoresaberScoresStore = create<ScoreSaberScoresStore>()(
|
|||||||
|
|
||||||
// Skip if we refreshed the scores recently
|
// Skip if we refreshed the scores recently
|
||||||
const timeUntilRefreshMs =
|
const timeUntilRefreshMs =
|
||||||
UPDATE_INTERVAL -
|
UPDATE_INTERVAL - (Date.now() - get().lastUpdated);
|
||||||
(Date.now() - useScoresaberScoresStore.getState().lastUpdated);
|
|
||||||
if (timeUntilRefreshMs > 0) {
|
if (timeUntilRefreshMs > 0) {
|
||||||
console.log(
|
console.log(
|
||||||
"Waiting",
|
"Waiting",
|
||||||
timeUntilRefreshMs / 1000,
|
timeUntilRefreshMs / 1000,
|
||||||
"seconds to refresh scores for players",
|
"seconds to refresh scores for players",
|
||||||
);
|
);
|
||||||
setTimeout(
|
setTimeout(() => get().updatePlayerScores(), timeUntilRefreshMs);
|
||||||
() => useScoresaberScoresStore.getState().updatePlayerScores(),
|
|
||||||
timeUntilRefreshMs,
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,7 +225,7 @@ export const useScoresaberScoresStore = create<ScoreSaberScoresStore>()(
|
|||||||
if (player == undefined) continue;
|
if (player == undefined) continue;
|
||||||
console.log(`Updating scores for ${player.id}...`);
|
console.log(`Updating scores for ${player.id}...`);
|
||||||
|
|
||||||
let oldScores = player.scores.scoresaber;
|
let oldScores: ScoresaberSmallerPlayerScore[] = player.scores;
|
||||||
|
|
||||||
// Sort the scores by date (newset to oldest), so we know when to stop searching for new scores
|
// Sort the scores by date (newset to oldest), so we know when to stop searching for new scores
|
||||||
oldScores = oldScores.sort((a, b) => {
|
oldScores = oldScores.sort((a, b) => {
|
||||||
@ -296,13 +292,13 @@ export const useScoresaberScoresStore = create<ScoreSaberScoresStore>()(
|
|||||||
|
|
||||||
let newPlayers = players;
|
let newPlayers = players;
|
||||||
// Remove the player if it already exists
|
// Remove the player if it already exists
|
||||||
newPlayers = newPlayers.filter((playerr) => playerr.id != player.id);
|
newPlayers = newPlayers.filter(
|
||||||
|
(playerr: Player) => playerr.id != player.id,
|
||||||
|
);
|
||||||
// Add the player
|
// Add the player
|
||||||
newPlayers.push({
|
newPlayers.push({
|
||||||
id: player.id,
|
id: player.id,
|
||||||
scores: {
|
scores: oldScores,
|
||||||
scoresaber: oldScores,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (newScoresCount > 0) {
|
if (newScoresCount > 0) {
|
||||||
@ -318,23 +314,8 @@ export const useScoresaberScoresStore = create<ScoreSaberScoresStore>()(
|
|||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
name: "scoresaberScores",
|
name: "scoresaberScores",
|
||||||
storage: createJSONStorage(() => localStorage),
|
storage: createJSONStorage(() => IDBStorage),
|
||||||
version: 1,
|
version: 1,
|
||||||
|
|
||||||
migrate: (state: any, version: number) => {
|
|
||||||
if (version == 1) {
|
|
||||||
state.players = state.players.map((player: any) => {
|
|
||||||
return {
|
|
||||||
id: player.id,
|
|
||||||
scores: {
|
|
||||||
scoresaber: player.scores,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -5,6 +5,7 @@ import { SortType, SortTypes } from "@/types/SortTypes";
|
|||||||
import { ScoreSaberAPI } from "@/utils/scoresaber/api";
|
import { ScoreSaberAPI } from "@/utils/scoresaber/api";
|
||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
import { createJSONStorage, persist } from "zustand/middleware";
|
import { createJSONStorage, persist } from "zustand/middleware";
|
||||||
|
import { IDBStorage } from "./IndexedDBStorage";
|
||||||
|
|
||||||
interface SettingsStore {
|
interface SettingsStore {
|
||||||
player: ScoresaberPlayer | undefined;
|
player: ScoresaberPlayer | undefined;
|
||||||
@ -19,14 +20,14 @@ interface SettingsStore {
|
|||||||
clearFriends: () => void;
|
clearFriends: () => void;
|
||||||
setLastUsedSortType: (sortType: SortType) => void;
|
setLastUsedSortType: (sortType: SortType) => void;
|
||||||
setProfilesLastUpdated: (profilesLastUpdated: number) => void;
|
setProfilesLastUpdated: (profilesLastUpdated: number) => void;
|
||||||
refreshProfiles: () => void;
|
refreshProfiles: () => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const UPDATE_INTERVAL = 1000 * 60 * 10; // 10 minutes
|
const UPDATE_INTERVAL = 1000 * 60 * 10; // 10 minutes
|
||||||
|
|
||||||
export const useSettingsStore = create<SettingsStore>()(
|
export const useSettingsStore = create<SettingsStore>()(
|
||||||
persist(
|
persist(
|
||||||
(set) => ({
|
(set, get) => ({
|
||||||
player: undefined,
|
player: undefined,
|
||||||
lastUsedSortType: SortTypes.top,
|
lastUsedSortType: SortTypes.top,
|
||||||
friends: [],
|
friends: [],
|
||||||
@ -39,7 +40,7 @@ export const useSettingsStore = create<SettingsStore>()(
|
|||||||
},
|
},
|
||||||
|
|
||||||
async addFriend(friendId: string) {
|
async addFriend(friendId: string) {
|
||||||
const friends = useSettingsStore.getState().friends;
|
const friends = this.friends;
|
||||||
if (friends.some((friend) => friend.id == friendId)) {
|
if (friends.some((friend) => friend.id == friendId)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -52,7 +53,7 @@ export const useSettingsStore = create<SettingsStore>()(
|
|||||||
},
|
},
|
||||||
|
|
||||||
removeFriend: (friendId: string) => {
|
removeFriend: (friendId: string) => {
|
||||||
const friends = useSettingsStore.getState().friends;
|
const friends = get().friends;
|
||||||
set({ friends: friends.filter((friend) => friend.id != friendId) });
|
set({ friends: friends.filter((friend) => friend.id != friendId) });
|
||||||
|
|
||||||
return friendId;
|
return friendId;
|
||||||
@ -61,7 +62,7 @@ export const useSettingsStore = create<SettingsStore>()(
|
|||||||
clearFriends: () => set({ friends: [] }),
|
clearFriends: () => set({ friends: [] }),
|
||||||
|
|
||||||
isFriend: (friendId: string) => {
|
isFriend: (friendId: string) => {
|
||||||
const friends: ScoresaberPlayer[] = useSettingsStore.getState().friends;
|
const friends: ScoresaberPlayer[] = get().friends;
|
||||||
return friends.some((friend) => friend.id == friendId);
|
return friends.some((friend) => friend.id == friendId);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -75,8 +76,7 @@ export const useSettingsStore = create<SettingsStore>()(
|
|||||||
|
|
||||||
async refreshProfiles() {
|
async refreshProfiles() {
|
||||||
const timeUntilRefreshMs =
|
const timeUntilRefreshMs =
|
||||||
UPDATE_INTERVAL -
|
UPDATE_INTERVAL - (Date.now() - get().profilesLastUpdated);
|
||||||
(Date.now() - useSettingsStore.getState().profilesLastUpdated);
|
|
||||||
if (timeUntilRefreshMs > 0) {
|
if (timeUntilRefreshMs > 0) {
|
||||||
console.log(
|
console.log(
|
||||||
"Waiting",
|
"Waiting",
|
||||||
@ -87,7 +87,7 @@ export const useSettingsStore = create<SettingsStore>()(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const player = useSettingsStore.getState().player;
|
const player = get().player;
|
||||||
if (player != undefined) {
|
if (player != undefined) {
|
||||||
const newPlayer = await ScoreSaberAPI.fetchPlayerData(player.id);
|
const newPlayer = await ScoreSaberAPI.fetchPlayerData(player.id);
|
||||||
if (newPlayer != undefined && newPlayer != null) {
|
if (newPlayer != undefined && newPlayer != null) {
|
||||||
@ -96,7 +96,7 @@ export const useSettingsStore = create<SettingsStore>()(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const friends = useSettingsStore.getState().friends;
|
const friends = get().friends;
|
||||||
const newFriends = await Promise.all(
|
const newFriends = await Promise.all(
|
||||||
friends.map(async (friend) => {
|
friends.map(async (friend) => {
|
||||||
const newFriend = await ScoreSaberAPI.fetchPlayerData(friend.id);
|
const newFriend = await ScoreSaberAPI.fetchPlayerData(friend.id);
|
||||||
@ -105,21 +105,12 @@ export const useSettingsStore = create<SettingsStore>()(
|
|||||||
return newFriend;
|
return newFriend;
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
set({ friends: newFriends });
|
set({ profilesLastUpdated: Date.now(), friends: newFriends });
|
||||||
|
|
||||||
useSettingsStore.setState({ profilesLastUpdated: Date.now() });
|
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
name: "settings",
|
name: "settings",
|
||||||
storage: createJSONStorage(() => localStorage),
|
storage: createJSONStorage(() => IDBStorage),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Refresh profiles every 10 minutes
|
|
||||||
useSettingsStore.getState().refreshProfiles();
|
|
||||||
setInterval(
|
|
||||||
() => useSettingsStore.getState().refreshProfiles(),
|
|
||||||
UPDATE_INTERVAL,
|
|
||||||
);
|
|
||||||
|
@ -118,7 +118,7 @@ export function calcPpBoundary(playerId: string, expectedPp = 1) {
|
|||||||
const rankedScores = useScoresaberScoresStore
|
const rankedScores = useScoresaberScoresStore
|
||||||
.getState()
|
.getState()
|
||||||
.players.find((p) => p.id === playerId)
|
.players.find((p) => p.id === playerId)
|
||||||
?.scores?.scoresaber.filter((s) => s.score.pp !== undefined);
|
?.scores?.filter((s) => s.score.pp !== undefined);
|
||||||
if (!rankedScores) return null;
|
if (!rankedScores) return null;
|
||||||
|
|
||||||
const rankedScorePps = rankedScores
|
const rankedScorePps = rankedScores
|
||||||
@ -159,7 +159,7 @@ export function getHighestPpPlay(playerId: string) {
|
|||||||
const rankedScores = useScoresaberScoresStore
|
const rankedScores = useScoresaberScoresStore
|
||||||
.getState()
|
.getState()
|
||||||
.players.find((p) => p.id === playerId)
|
.players.find((p) => p.id === playerId)
|
||||||
?.scores?.scoresaber.filter((s) => s.score.pp !== undefined);
|
?.scores?.filter((s) => s.score.pp !== undefined);
|
||||||
if (!rankedScores) return null;
|
if (!rankedScores) return null;
|
||||||
|
|
||||||
const rankedScorePps = rankedScores
|
const rankedScorePps = rankedScores
|
||||||
@ -179,7 +179,7 @@ export function getAveragePp(playerId: string, limit: number = 20) {
|
|||||||
const rankedScores = useScoresaberScoresStore
|
const rankedScores = useScoresaberScoresStore
|
||||||
.getState()
|
.getState()
|
||||||
.players.find((p) => p.id === playerId)
|
.players.find((p) => p.id === playerId)
|
||||||
?.scores?.scoresaber.filter((s) => s.score.pp !== undefined);
|
?.scores?.filter((s) => s.score.pp !== undefined);
|
||||||
if (!rankedScores) return null;
|
if (!rankedScores) return null;
|
||||||
|
|
||||||
const rankedScorePps = rankedScores
|
const rankedScorePps = rankedScores
|
||||||
|
Loading…
Reference in New Issue
Block a user