Hi!
I’ve been developing an app (React, Ionic 6) that gives rankings to the user and lets them update them for ranking predictions. I also save the data gotten when the rankings are fetched to Ionic Storage, so the user is able to restore data once the app is reloaded.
This is the screen that is shown when the app has been loaded:
As seen, the user needs to manually click “Restore Data” after reloading the app. Is there a way to run the restore data function at the beginning of the program?
App.tsx code
import { Redirect, Route } from 'react-router-dom';
import {
IonApp,
IonIcon,
IonLabel,
IonRouterOutlet,
IonTabBar,
IonTabButton,
IonTabs,
setupIonicReact
} from '@ionic/react';
import { IonReactRouter } from '@ionic/react-router';
import { /*ellipse, square,*/ triangle } from 'ionicons/icons';
import Rankings from './pages/Rankings';
// import Tab2 from './pages/Tab2';
// import Tab3 from './pages/Tab3';
/* Core CSS required for Ionic components to work properly */
import '@ionic/react/css/core.css';
/* Basic CSS for apps built with Ionic */
import '@ionic/react/css/normalize.css';
import '@ionic/react/css/structure.css';
import '@ionic/react/css/typography.css';
/* Optional CSS utils that can be commented out */
import '@ionic/react/css/padding.css';
import '@ionic/react/css/float-elements.css';
import '@ionic/react/css/text-alignment.css';
import '@ionic/react/css/text-transformation.css';
import '@ionic/react/css/flex-utils.css';
import '@ionic/react/css/display.css';
/* Theme variables */
import './theme/variables.css';
setupIonicReact();
const App: React.FC = () => (
<IonApp>
<IonReactRouter>
<IonTabs>
<IonRouterOutlet>
<Route exact path="/rankings">
<Rankings />
</Route>
<Route exact path="/">
<Redirect to="/rankings" />
</Route>
</IonRouterOutlet>
<IonTabBar slot="bottom">
<IonTabButton tab="rankings" href="/rankings">
<IonIcon icon={triangle} />
<IonLabel>Rankings</IonLabel>
</IonTabButton>
</IonTabBar>
</IonTabs>
</IonReactRouter>
</IonApp>
);
export default App;
Rankings.tsx code (the main tab element)
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar, IonList, IonItem, IonLabel, IonInput, IonButton, IonGrid, IonCol, IonRow } from '@ionic/react';
import { Storage } from '@ionic/storage';
import { useState } from 'react';
import { events } from 'robotevents-api';
import './Rankings.css';
import { Rankings } from 'robotevents-api/lib/api/rankings';
const store = new Storage();
store.create();
const RankingsTab: React.FC = () => {
const [inputSKU1, setInputSKU1] = useState<string | undefined>("VRC");
const [inputSKU2, setInputSKU2] = useState<string | undefined>("22");
const [inputSKU3, setInputSKU3] = useState<string | undefined>("0008");
const [division, setDivision] = useState<string | undefined>("1");
const [dataRestored, setDataRestored] = useState<boolean>(false);
const [actualRankings, setActualRankings] = useState<Rankings[]>([]);
const [rankings, setRankings] = useState<Rankings[]>([]);
const restoreData = async () => {
const json: Rankings[] = await store.get('rankings');
console.log('Rankings have been recieved from local storage.');
setInputSKU1(await store.get("Input SKU 1"));
setInputSKU2(await store.get("Input SKU 2"));
setInputSKU3(await store.get("Input SKU 3"));
setDivision(await store.get("Division"));
console.log('Input data has been recieved from local storage.');
setActualRankings(json.reverse())
setRankings(organizeRankings(json));
setDataRestored(true);
};
const getData = async () => {
if ( inputSKU1 == undefined || inputSKU1 == "" ||
inputSKU2 == undefined || inputSKU2 == "" ||
inputSKU3 == undefined || inputSKU3 == "") {
alert("Please enter in the event SKU.");
return;
}
const json: Rankings[] = await (await events.get(`RE-${inputSKU1}-${inputSKU2}-${inputSKU3}`)).rankings({ divId: parseInt(division!) || 1 });
for (let i = 0; i < json.length; i++) { // @ts-ignore
json[i].wpcolor = 'inherit'; // @ts-ignore
json[i].apcolor = 'inherit'; // @ts-ignore
json[i].spcolor = 'inherit';
}
setActualRankings(json.reverse())
setRankings(organizeRankings(json));
setDataRestored(true);
await store.set('rankings', json);
console.log('Rankings have been saved to local storage.');
await store.set("Input SKU 1", inputSKU1);
await store.set("Input SKU 2", inputSKU2);
await store.set("Input SKU 3", inputSKU3);
await store.set("Division", division);
console.log('Input data has been saved to local storage.');
};
const organizeRankings = (ranking: Rankings[]) => {
let newRanking: Rankings[] = [];
for (let i = 0; i < ranking.length; i++) {
let inserted = false;
for (let j = 0; j < newRanking.length; j++) {
if (ranking[i].wp > newRanking[j].wp) inserted = true;
else if (ranking[i].wp == newRanking[j].wp) {
if (ranking[i].ap > newRanking[j].ap) inserted = true;
else if (ranking[i].ap == newRanking[j].ap && ranking[i].sp > newRanking[j].sp) inserted = true;
}
if (inserted) {
newRanking = newRanking.slice(0, j)
.concat(ranking[i])
.concat(newRanking.slice(j));
break;
}
}
if (!inserted) newRanking.push(ranking[i]);
}
return newRanking
};
const reset = () => {
setRankings(organizeRankings(actualRankings));
};
const changeState = (name: string, str: string | number | undefined | null, callback: Function) => {
console.log(`'${name}' = '${str}'`);
if (typeof str == 'string')
callback(str);
callback(str?.toString());
};
const changeRankings = (name: string, str: string | number | undefined | null, index: number) => {
console.log(`'${index}-${name}' = '${str}'`);
const newRankings = JSON.parse(JSON.stringify(rankings));
if (str == '') { // @ts-ignore
newRankings[index][name] = actualRankings[newRankings[index].rank - 1][name];
}
else if (typeof str == 'number')
newRankings[index][name] = str;
else if (parseInt(str!).toString().length != str!.length) { // @ts-ignore
newRankings[index][name] = actualRankings[newRankings[index].rank - 1][name];
}
else
newRankings[index][name] = parseInt(str!);
// @ts-ignore
if (actualRankings[newRankings[index].rank - 1][name] == newRankings[index][name])
newRankings[index][`${name}color`] = 'inherit'; // @ts-ignore
else if (actualRankings[newRankings[index].rank - 1][name] > newRankings[index][name])
newRankings[index][`${name}color`] = 'red';
else
newRankings[index][`${name}color`] = 'lightgreen';
setRankings(organizeRankings(newRankings));
}
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonTitle>Rankings</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent fullscreen>
<IonHeader collapse="condense">
<IonToolbar>
<IonTitle size="large">Rankings</IonTitle>
</IonToolbar>
</IonHeader>
<IonList>
<IonItem>
<IonLabel>Event SKU/Code:</IonLabel>
<IonInput class="top" readonly value="RE"></IonInput>
<IonLabel>-</IonLabel>
<IonInput class="top" type="text" value={inputSKU1} placeholder="XXX" onIonChange={e => changeState("Input SKU 1", e.target.value!, setInputSKU1)}></IonInput>
<IonLabel>-</IonLabel>
<IonInput class="top" type="number" value={inputSKU2} placeholder="00" onIonChange={e => changeState("Input SKU 2", e.target.value!, setInputSKU2)}></IonInput>
<IonLabel>-</IonLabel>
<IonInput class="top" type="number" value={inputSKU3} placeholder="0000" onIonChange={e => changeState("Input SKU 3", e.target.value!, setInputSKU3)}></IonInput>
</IonItem>
<IonItem>
<IonLabel>Division: </IonLabel>
<IonInput class="left" value={division} placeholder="1" onIonChange={e => changeState("Division", e.target.value!, setDivision)}></IonInput>
</IonItem>
<IonItem>
<IonLabel></IonLabel>
<IonButton onClick={getData} shape="round" size="default" color="success">Refresh Competition</IonButton>
<IonButton onClick={reset} shape="round" size="default" color="warning">Reset</IonButton>
<IonLabel></IonLabel>
</IonItem>
</IonList>
<hr></hr>
<IonGrid>
<IonRow class="header">
<IonCol size="1.2">#</IonCol>
<IonCol size="2.8">Number</IonCol>
<IonCol size="2.6">W-L-T</IonCol>
<IonCol size="1.8">WP</IonCol>
<IonCol size="1.8">AP</IonCol>
<IonCol size="1.8">SP</IonCol>
</IonRow>
<IonRow><IonCol><IonButton hidden={dataRestored} onClick={restoreData} shape="round" size="default" color="danger">Restore Data</IonButton></IonCol></IonRow>
{
rankings.map((singleRanking, index) => (
<IonRow key={singleRanking.team.id}>
<IonCol size="1.2">{singleRanking.rank}</IonCol>
<IonCol size="2.8">{singleRanking.team.name}</IonCol>
<IonCol size="2.6">{singleRanking.wins}-{singleRanking.losses}-{singleRanking.ties}</IonCol> {/*@ts-ignore*/}
<IonCol size="1.8"><IonInput type="number" class="teamlist" style={{color: singleRanking.wpcolor}} value={singleRanking.wp} placeholder={actualRankings[rankings[index].rank - 1]?.wp?.toString() || "0"} onKeyUp={e => { if (e.key === 'Enter') changeRankings('wp', e.target.value, index); }} onIonBlur={e => changeRankings('wp', e.target.value, index)}></IonInput></IonCol> {/*@ts-ignore*/}
<IonCol size="1.8"><IonInput type="number" class="teamlist" style={{color: singleRanking.apcolor}} value={singleRanking.ap} placeholder={actualRankings[rankings[index].rank - 1]?.ap?.toString() || "0"} onKeyUp={e => { if (e.key === 'Enter') changeRankings('ap', e.target.value, index); }} onIonBlur={e => changeRankings('ap', e.target.value, index)}></IonInput></IonCol> {/*@ts-ignore*/}
<IonCol size="1.8"><IonInput type="number" class="teamlist" style={{color: singleRanking.spcolor}} value={singleRanking.sp} placeholder={actualRankings[rankings[index].rank - 1]?.sp?.toString() || "0"} onKeyUp={e => { if (e.key === 'Enter') changeRankings('sp', e.target.value, index); }} onIonBlur={e => changeRankings('sp', e.target.value, index)}></IonInput></IonCol>
</IonRow>
))
}
</IonGrid>
</IonContent>
</IonPage>
);
};
export default RankingsTab;
The Rankings.tsx file contains the restoreData function towards the beginning of the file.
Thanks in advance!