Update requirement files with new feature templates and fix backend API error message, along with mobile project config updates and documentation improvements

This commit is contained in:
louiscklaw
2025-06-13 12:11:47 +08:00
parent f23a6b7d9c
commit 346992d4ec
3102 changed files with 220182 additions and 2896 deletions

View File

@@ -18,10 +18,10 @@ import { SkeletonDashboard } from '../TestComponents/SkeletonDashboard';
import { chevronBackOutline, refreshOutline } from 'ionicons/icons';
import { CurrentWeather } from '../TestComponents/CurrentWeather';
function Tab1() {
const Tab1: React.FC = () => {
const router = useIonRouter();
const [currentWeather, setCurrentWeather] = useState(false);
const [currentWeather, setCurrentWeather] = useState<any>(false);
useEffect(() => {
getCurrentPosition();
@@ -33,7 +33,7 @@ function Tab1() {
getAddress(coordinates.coords);
};
const getAddress = async (coords) => {
const getAddress = async (coords: any) => {
const query = `${coords.latitude},${coords.longitude}`;
const response = await fetch(
`https://api.weatherapi.com/v1/current.json?key=f93eb660b2424258bf5155016210712&q=${query}`
@@ -91,6 +91,6 @@ function Tab1() {
</IonContent>
</IonPage>
);
}
};
export default Tab1;

View File

@@ -12,15 +12,15 @@ import {
import { useState } from 'react';
import { CurrentWeather } from '../TestComponents/CurrentWeather';
function Tab2() {
const [search, setSearch] = useState('');
const [currentWeather, setCurrentWeather] = useState(false);
const Tab2: React.FC = () => {
const [search, setSearch] = useState<any>('');
const [currentWeather, setCurrentWeather] = useState<any>(false);
const performSearch = async () => {
getAddress(search);
};
const getAddress = async (city) => {
const getAddress = async (city: any) => {
const response = await fetch(
`https://api.weatherapi.com/v1/current.json?key=f93eb660b2424258bf5155016210712&q=${city}&aqi=no`
);
@@ -51,7 +51,7 @@ function Tab2() {
placeholder="Try 'London'"
animated
value={search}
onIonChange={(e) => setSearch(e.target.value)}
onIonChange={(e: any) => setSearch(e.target.value)}
/>
</IonCol>
@@ -76,6 +76,6 @@ function Tab2() {
</IonContent>
</IonPage>
);
}
};
export default Tab2;

View File

@@ -2,8 +2,62 @@ import { IonCardSubtitle, IonCol, IonIcon, IonNote, IonRow } from '@ionic/react'
import { pulseOutline, sunnyOutline, thermometerOutline } from 'ionicons/icons';
import { useEffect, useState } from 'react';
export const WeatherProperty = ({ type, currentWeather }: { type: any; currentWeather: any }) => {
const [property, setProperty] = useState(false);
interface CurrentWeather {
current: {
wind_mph: number;
feelslike_c: number;
uv: number;
pressure_mb: number;
};
}
interface PropertyItem {
isIcon: boolean;
icon: string;
alt: string;
label: string;
value: string | number;
}
const properties = {
wind: {
isIcon: true,
icon: 'wind-outline',
alt: 'wind',
label: 'Wind',
value: '0 km/h',
},
feelsLike: {
isIcon: true,
icon: 'thermometer-outline',
alt: 'feels like',
label: 'Feels Like',
value: '0°C',
},
indexUV: {
isIcon: true,
icon: 'sunny-outline',
alt: 'UV index',
label: 'UV Index',
value: 0,
},
pressure: {
isIcon: false,
icon: '',
alt: '',
label: 'Pressure',
value: '0 hPa',
},
} as const;
export const WeatherProperty = ({
type,
currentWeather,
}: {
type: keyof typeof properties;
currentWeather: CurrentWeather;
}) => {
const [property, setProperty] = useState<PropertyItem | null>(null);
const properties = {
wind: {
@@ -37,9 +91,13 @@ export const WeatherProperty = ({ type, currentWeather }: { type: any; currentWe
};
useEffect(() => {
setProperty(properties[type]);
setProperty(properties[type as keyof typeof properties]);
}, [type]);
if (!property) {
return null;
}
return (
<IonCol size="6">
<IonRow className="ion-justify-content-center ion-align-items-center">

View File

@@ -1,7 +1,15 @@
import { IonAvatar, IonButton, IonItem, IonLabel } from '@ionic/react';
import { toggleFollowing } from '../store/PeopleStore';
export const Person = ({ person }): React.JSX.Element => {
interface Person {
id: string;
name: string;
title: string;
avatar: string;
following: boolean;
}
export const Person = ({ person }: { person: Person }): React.JSX.Element => {
return (
<IonItem lines="full">
<IonAvatar>

View File

@@ -1,45 +0,0 @@
export const people = [
{
id: 1,
name: "Alan Montgomery",
title: "Mobile Team Lead",
avatar: "https://pbs.twimg.com/profile_images/1420489989163524096/GwHdYSky_400x400.jpg",
following: false
},
{
id: 2,
name: "Max Lynch",
title: "CEO | Co Founder",
avatar: "https://pbs.twimg.com/profile_images/1318970727173885953/bln98FNj_400x400.jpg",
following: false
},
{
id: 3,
name: "Mike Hartington",
title: "Senior Dev Rel",
avatar: "https://pbs.twimg.com/profile_images/1084993841898446849/DJ8XtR6L_400x400.jpg",
following: false
},
{
id: 4,
name: "Matt Netkow",
title: "Head of Product Marketing",
avatar: "https://pbs.twimg.com/profile_images/1323383930150621187/GKc0nVzi_400x400.jpg",
following: false
},
{
id: 5,
name: "Ben Sperry",
title: "CDO | Co Founder",
avatar: "https://pbs.twimg.com/profile_images/1407747959345795072/McJb-RvC_400x400.jpg",
following: false
},
{
id: 6,
name: "Liam DeBeasi",
title: "Software Engineer",
avatar: "https://pbs.twimg.com/profile_images/1105953692669366273/ZNK4lRAJ_400x400.jpg",
following: false
}
];

View File

@@ -0,0 +1,44 @@
export const people: any = [
{
id: 1,
name: 'Alan Montgomery',
title: 'Mobile Team Lead',
avatar: 'https://pbs.twimg.com/profile_images/1420489989163524096/GwHdYSky_400x400.jpg',
following: false,
},
{
id: 2,
name: 'Max Lynch',
title: 'CEO | Co Founder',
avatar: 'https://pbs.twimg.com/profile_images/1318970727173885953/bln98FNj_400x400.jpg',
following: false,
},
{
id: 3,
name: 'Mike Hartington',
title: 'Senior Dev Rel',
avatar: 'https://pbs.twimg.com/profile_images/1084993841898446849/DJ8XtR6L_400x400.jpg',
following: false,
},
{
id: 4,
name: 'Matt Netkow',
title: 'Head of Product Marketing',
avatar: 'https://pbs.twimg.com/profile_images/1323383930150621187/GKc0nVzi_400x400.jpg',
following: false,
},
{
id: 5,
name: 'Ben Sperry',
title: 'CDO | Co Founder',
avatar: 'https://pbs.twimg.com/profile_images/1407747959345795072/McJb-RvC_400x400.jpg',
following: false,
},
{
id: 6,
name: 'Liam DeBeasi',
title: 'Software Engineer',
avatar: 'https://pbs.twimg.com/profile_images/1105953692669366273/ZNK4lRAJ_400x400.jpg',
following: false,
},
];

View File

@@ -9,7 +9,7 @@ import {
IonToolbar,
useIonRouter,
} from '@ionic/react';
import { PeopleStore } from '../store';
import PeopleStore from '../store/PeopleStore';
import { Person } from '../components/Person';
import './Tab1.css';
import { useStoreState } from 'pullstate';
@@ -52,7 +52,7 @@ const Tab1 = (): React.JSX.Element => {
</IonToolbar>
</IonHeader>
{people.map((person, index) => {
{people.map((person: any, index: number) => {
return <Person person={person} key={index} />;
})}
</IonContent>

View File

@@ -1,7 +1,7 @@
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar } from '@ionic/react';
import { useStoreState } from 'pullstate';
import { Person } from '../components/Person';
import { PeopleStore } from '../store';
import PeopleStore from '../store/PeopleStore';
import { getFollowing } from '../store/Selectors';
import './Tab2.css';
import React from 'react';
@@ -23,7 +23,7 @@ const Tab2 = (): React.JSX.Element => {
</IonToolbar>
</IonHeader>
{people.map((person, index) => {
{people.map((person: any, index: number) => {
return <Person person={person} key={index} />;
})}
</IonContent>

View File

@@ -1,19 +0,0 @@
import { Store } from "pullstate";
import { people } from "../data";
const PeopleStore = new Store({
people: people
});
export const toggleFollowing = personId => {
PeopleStore.update(s => {
const personIndex = s.people.findIndex(person => person.id === personId);
s.people[personIndex].following = !s.people[personIndex].following;
});
}
export default PeopleStore;

View File

@@ -0,0 +1,16 @@
import { Store } from 'pullstate';
import { people } from '../data';
const PeopleStore = new Store({
people: people,
});
export const toggleFollowing = (personId: any) => {
PeopleStore.update((s: any) => {
const personIndex = s.people.findIndex((person: any) => person.id === personId);
s.people[personIndex].following = !s.people[personIndex].following;
});
};
export default PeopleStore;

View File

@@ -1,7 +0,0 @@
import { createSelector } from "reselect";
const getState = state => state;
// Gets
export const getPeople = createSelector(getState, state => state.people);
export const getFollowing = createSelector(getState, state => state.people.filter(person => person.following));

View File

@@ -0,0 +1,9 @@
import { createSelector } from 'reselect';
const getState = (state: any) => state;
// Gets
export const getPeople = createSelector(getState, (state) => state.people);
export const getFollowing = createSelector(getState, (state) =>
state.people.filter((person: any) => person.following)
);

View File

@@ -1 +0,0 @@
export { default as PeopleStore } from "./PeopleStore";