part4
Tony Fages 1 year ago
parent 90fa0557b0
commit 83196ed2be

@ -3,14 +3,18 @@ import React from "react";
import {ListJokeScreen} from "./screens/ListJokeScreen"; import {ListJokeScreen} from "./screens/ListJokeScreen";
import {Navigation} from "./navigation/Navigation"; import {Navigation} from "./navigation/Navigation";
import {darksalmonColor, indigo, purpleColor} from "./Theme"; import {darksalmonColor, indigo, purpleColor} from "./Theme";
import {Provider} from "react-redux";
import store from "./redux/store";
export default function App() { export default function App() {
return ( return (
<Provider store={store}>
<SafeAreaView style={styles.container}> <SafeAreaView style={styles.container}>
<StatusBar barStyle="light-content" /> <StatusBar barStyle="light-content" />
<Navigation/> <Navigation/>
</SafeAreaView> </SafeAreaView>
</Provider>
); );
} }

@ -1,20 +1,21 @@
import {Joke} from "../model/Joke"; import {Joke} from "../model/Joke";
import {Image, StyleSheet, Text, View} from "react-native"; import {Image, StyleSheet, Text, View} from "react-native";
import React from "react"; import React from "react";
import {indigo} from "../Theme"; import {greyColor, indigo} from "../Theme";
import {Categorie} from "../model/Categorie";
type JokeListItemProps = { type ListAllCategories = {
item: String; item: Categorie;
} }
export function ListAllCategories(props: JokeListItemProps) { export function ListAllCategories(props: ListAllCategories) {
return ( return (
<View style={styles.listItem}> <View style={styles.listItem}>
<View style={styles.chip}> <View style={styles.chip}>
<Text>{props.item}</Text> <Text>{props.item.name}</Text>
</View> </View>
</View> </View>
); );
@ -30,7 +31,7 @@ const styles = StyleSheet.create({
}, },
chip: { chip: {
borderRadius: 16, borderRadius: 16,
backgroundColor: 'rgba(140, 140, 161, 1)', backgroundColor: greyColor,
padding: 5, padding: 5,
marginTop: 5, marginTop: 5,
alignSelf: 'flex-start', alignSelf: 'flex-start',

@ -0,0 +1,24 @@
import {Joke} from "./Joke";
export class Categorie{
private _name : string;
private _number : number;
get name(): string {
return this._name;
}
get number(): number {
return this._number;
}
public constructor(name :string, number :number) {
this._name = name;
this._number = number;
}
}

@ -0,0 +1,12 @@
import {Categorie} from "./Categorie";
export class CategorieFactory {
public static createCategories(jsonArray: string): Categorie[] {
let array = [];
let json = JSON.parse(jsonArray);
json.forEach(function (categorie) {
array.push(new Categorie(categorie.name, categorie.number));
});
return array;
}
}

@ -1,5 +1,6 @@
import { CustomJoke } from "./CustomJoke"; import { CustomJoke } from "./CustomJoke";
import { SampleJoke } from "./SampleJoke"; import { SampleJoke } from "./SampleJoke";
import {Categorie} from "./Categorie";
export class JokeFactory { export class JokeFactory {
@ -25,6 +26,4 @@ export class JokeFactory {
return array; return array;
} }
} }

@ -12,12 +12,15 @@
"@react-navigation/bottom-tabs": "^6.5.11", "@react-navigation/bottom-tabs": "^6.5.11",
"@react-navigation/native": "^6.1.9", "@react-navigation/native": "^6.1.9",
"@react-navigation/stack": "^6.3.20", "@react-navigation/stack": "^6.3.20",
"@reduxjs/toolkit": "^2.2.1",
"@types/react": "~18.2.45", "@types/react": "~18.2.45",
"expo": "~50.0.3", "expo": "~50.0.3",
"expo-status-bar": "~1.11.1", "expo-status-bar": "~1.11.1",
"react": "18.2.0", "react": "18.2.0",
"react-native": "0.73.2", "react-native": "0.73.2",
"react-native-gesture-handler": "^2.15.0", "react-native-gesture-handler": "^2.15.0",
"react-redux": "^9.1.0",
"redux": "^5.0.1",
"typescript": "^5.3.0" "typescript": "^5.3.0"
}, },
"devDependencies": { "devDependencies": {
@ -6244,6 +6247,29 @@
"react-native-screens": ">= 3.0.0" "react-native-screens": ">= 3.0.0"
} }
}, },
"node_modules/@reduxjs/toolkit": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.1.tgz",
"integrity": "sha512-8CREoqJovQW/5I4yvvijm/emUiCCmcs4Ev4XPWd4mizSO+dD3g5G6w34QK5AGeNrSH7qM8Fl66j4vuV7dpOdkw==",
"dependencies": {
"immer": "^10.0.3",
"redux": "^5.0.1",
"redux-thunk": "^3.1.0",
"reselect": "^5.0.1"
},
"peerDependencies": {
"react": "^16.9.0 || ^17.0.0 || ^18",
"react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0"
},
"peerDependenciesMeta": {
"react": {
"optional": true
},
"react-redux": {
"optional": true
}
}
},
"node_modules/@segment/loosely-validate-event": { "node_modules/@segment/loosely-validate-event": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/@segment/loosely-validate-event/-/loosely-validate-event-2.0.0.tgz", "resolved": "https://registry.npmjs.org/@segment/loosely-validate-event/-/loosely-validate-event-2.0.0.tgz",
@ -6411,6 +6437,11 @@
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz",
"integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==" "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw=="
}, },
"node_modules/@types/use-sync-external-store": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
"integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA=="
},
"node_modules/@types/yargs": { "node_modules/@types/yargs": {
"version": "17.0.32", "version": "17.0.32",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz",
@ -8839,6 +8870,15 @@
"node": ">=16.x" "node": ">=16.x"
} }
}, },
"node_modules/immer": {
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/immer/-/immer-10.0.3.tgz",
"integrity": "sha512-pwupu3eWfouuaowscykeckFmVTpqbzW+rXFCX8rQLkZzM9ftBmU/++Ra+o+L27mz03zJTlyV4UUr+fdKNffo4A==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/immer"
}
},
"node_modules/import-fresh": { "node_modules/import-fresh": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
@ -12062,6 +12102,32 @@
"async-limiter": "~1.0.0" "async-limiter": "~1.0.0"
} }
}, },
"node_modules/react-redux": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.0.tgz",
"integrity": "sha512-6qoDzIO+gbrza8h3hjMA9aq4nwVFCKFtY2iLxCtVT38Swyy2C/dJCGBXHeHLtx6qlg/8qzc2MrhOeduf5K32wQ==",
"dependencies": {
"@types/use-sync-external-store": "^0.0.3",
"use-sync-external-store": "^1.0.0"
},
"peerDependencies": {
"@types/react": "^18.2.25",
"react": "^18.0",
"react-native": ">=0.69",
"redux": "^5.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"react-native": {
"optional": true
},
"redux": {
"optional": true
}
}
},
"node_modules/react-refresh": { "node_modules/react-refresh": {
"version": "0.14.0", "version": "0.14.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz",
@ -12123,6 +12189,19 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/redux": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w=="
},
"node_modules/redux-thunk": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz",
"integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==",
"peerDependencies": {
"redux": "^5.0.0"
}
},
"node_modules/regenerate": { "node_modules/regenerate": {
"version": "1.4.2", "version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@ -12234,6 +12313,11 @@
"path-parse": "^1.0.5" "path-parse": "^1.0.5"
} }
}, },
"node_modules/reselect": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.0.tgz",
"integrity": "sha512-aw7jcGLDpSgNDyWBQLv2cedml85qd95/iszJjN988zX1t7AVRJi19d9kto5+W7oCfQ94gyo40dVbT6g2k4/kXg=="
},
"node_modules/resolve": { "node_modules/resolve": {
"version": "1.22.8", "version": "1.22.8",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
@ -13361,6 +13445,14 @@
"react": ">=16.8" "react": ">=16.8"
} }
}, },
"node_modules/use-sync-external-store": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
"integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/util-deprecate": { "node_modules/util-deprecate": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",

@ -13,12 +13,15 @@
"@react-navigation/bottom-tabs": "^6.5.11", "@react-navigation/bottom-tabs": "^6.5.11",
"@react-navigation/native": "^6.1.9", "@react-navigation/native": "^6.1.9",
"@react-navigation/stack": "^6.3.20", "@react-navigation/stack": "^6.3.20",
"@reduxjs/toolkit": "^2.2.1",
"@types/react": "~18.2.45", "@types/react": "~18.2.45",
"expo": "~50.0.3", "expo": "~50.0.3",
"expo-status-bar": "~1.11.1", "expo-status-bar": "~1.11.1",
"react": "18.2.0", "react": "18.2.0",
"react-native": "0.73.2", "react-native": "0.73.2",
"react-native-gesture-handler": "^2.15.0", "react-native-gesture-handler": "^2.15.0",
"react-redux": "^9.1.0",
"redux": "^5.0.1",
"typescript": "^5.3.0" "typescript": "^5.3.0"
}, },
"devDependencies": { "devDependencies": {

@ -0,0 +1,33 @@
import {Categorie} from "../../model/Categorie";
import {CategorieFactory} from "../../model/CategorieFactory";
export enum CategoriesActionType {
FETCH_CATEGORIES = 'FETCH_CATEGORIES',
}
export interface CategoriesAction {
type: CategoriesActionType;
payload: Categorie[];
}
export type Action = CategoriesAction;
export const setCategories = (categories: Categorie[]): CategoriesAction => {
return {
type: CategoriesActionType.FETCH_CATEGORIES,
payload: categories
}
}
export const getCategorie = async() : Promise<Categorie[]> => {
try {
const categories = await fetch('https://iut-weather-api.azurewebsites.net/jokes/categories/top');
const categorieJson = await categories.text();
return CategorieFactory.createCategories(categorieJson);
}
catch (error) {
console.log('Error---------', error);
}
}

@ -0,0 +1,52 @@
import {SampleJoke} from "../../model/SampleJoke";
import {JokeFactory} from "../../model/JokeFactory";
export enum SampleActionType {
FETCH_SAMPLE = 'FETCH_SAMPLE',
FECTH_LAST_JOKES = 'FECTH_LAST_JOKES'
}
export interface SampleAction {
type: SampleActionType;
payload: SampleJoke[];
}
export type Action = SampleAction;
export const setSample = (sample: SampleJoke[]): SampleAction => {
return {
type: SampleActionType.FETCH_SAMPLE,
payload: sample
}
}
export const setRecentJokes = (recentJokes: SampleJoke[]): SampleAction => {
return {
type: SampleActionType.FECTH_LAST_JOKES,
payload: recentJokes
}
}
export const getSampleJoke = async() : Promise<SampleJoke[]> => {
try {
const sample = await fetch('https://iut-weather-api.azurewebsites.net/jokes/samples');
const sampleJson = await sample.text();
return JokeFactory.createSampleJokes(sampleJson);
}
catch (error) {
console.log('Error---------', error);
}
}
export const getLatestJokes = async() : Promise<SampleJoke[]> => {
try {
const sample = await fetch('https://iut-weather-api.azurewebsites.net/jokes/lasts');
const sampleJson = await sample.text();
return JokeFactory.createSampleJokes(sampleJson);
}
catch (error) {
console.log('Error---------', error);
}
}

@ -0,0 +1,22 @@
import {Action, CategoriesActionType} from "../actions/categoriesAction";
import {Categorie} from "../../model/Categorie";
interface State {
categories: Categorie[];
}
const initialState: State = {
categories: [],
}
// @ts-ignore
export default appReducer = (state = initialState, action: Action) => {
switch (action.type) {
case CategoriesActionType.FETCH_CATEGORIES:
return {
...state,
categories: action.payload
}
default:
return state;
}
}

@ -0,0 +1,32 @@
import {SampleJoke} from "../../model/SampleJoke";
import {Action, SampleActionType} from "../actions/sampleAction";
interface state {
sampleJoke: SampleJoke[];
recentJokes: SampleJoke[];
}
const initialState: state = {
sampleJoke: [],
recentJokes: [],
}
// @ts-ignore
export default appReducer = (state = initialState, action: Action) => {
switch (action.type) {
case SampleActionType.FETCH_SAMPLE:
return {
...state,
sampleJoke: action.payload
}
case SampleActionType.FECTH_LAST_JOKES:
return {
...state,
recentJokes: action.payload
}
default:
return state;
}
}

@ -0,0 +1,19 @@
import { configureStore } from '@reduxjs/toolkit';
import categorieReducer from './reducers/categoryReducer';
import sampleReducer from './reducers/sampleJokeReducer';
const reducer = {
categorieReducer: categorieReducer,
sampleReducer: sampleReducer
};
// @ts-ignore
const store = configureStore({
reducer: reducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: false
})
});
export default store;

@ -1,28 +1,35 @@
import {FlatList, Image, SafeAreaView, ScrollView, SectionListComponent, StyleSheet, Text, View} from "react-native"; import {FlatList, Image, SafeAreaView, ScrollView, SectionListComponent, StyleSheet, Text, View} from "react-native";
import {indigo, purpleColor} from "../Theme"; import {indigo, purpleColor} from "../Theme";
import {Joke} from "../model/Joke"; import {Joke} from "../model/Joke";
import {DataGen, ListJokeScreen} from "./ListJokeScreen"; import React, {useEffect} from "react";
import React from "react";
import {HorizontalListJokeComponent} from "../components/HorizontalListJokeComponent"; import {HorizontalListJokeComponent} from "../components/HorizontalListJokeComponent";
import {ListAllCategories} from "../components/ListAllCategories"; import {ListAllCategories} from "../components/ListAllCategories";
import {CustomJoke} from "../model/CustomJoke"; import {CustomJoke} from "../model/CustomJoke";
import {JokeFactory} from "../model/JokeFactory";
import {JokeStub} from "../model/JokeStub";
import {useDispatch, useSelector} from "react-redux";
import {getLatestJokes, getSampleJoke, setRecentJokes, setSample} from "../redux/actions/sampleAction";
import {getCategorie, setCategories} from "../redux/actions/categoriesAction";
import {Categorie} from "../model/Categorie";
let taille = DataGen.length;
let LastJokes = DataGen.slice(taille - 20, taille);
function filterCategory(jokes: Joke[]): String[] {
let categories: String[] = [];
jokes.forEach(joke => {
if (!categories.includes(joke.type())) {
categories.push(joke.type());
}
});
return categories;
}
export function AccueilScreen() { export function AccueilScreen() {
// Permet de filtrer les types des blagues pour les afficher dans la liste des categories const DataGen = useSelector((state: any) => state.sampleReducer.recentJokes);
const FiltereData = filterCategory(LastJokes); const DataCate = useSelector((state: any) => state.categorieReducer.categories);
const dispatch = useDispatch();
useEffect(() => {
const getJokes = async () => {
dispatch(setRecentJokes(await getLatestJokes()));
};
getJokes();
const getTopCategories = async () => {
dispatch(setCategories(await getCategorie()));
};
getTopCategories();
}, [dispatch]);
return ( return (
<SafeAreaView style={styles.container}> <SafeAreaView style={styles.container}>
@ -33,7 +40,7 @@ export function AccueilScreen() {
<Text style={styles.titleAccueil}>Dernieres Blagues</Text> <Text style={styles.titleAccueil}>Dernieres Blagues</Text>
</View> </View>
<FlatList showsHorizontalScrollIndicator={false} horizontal={true} <FlatList showsHorizontalScrollIndicator={false} horizontal={true}
data={LastJokes} data={DataGen}
renderItem={HorizontalListJokeComponent} renderItem={HorizontalListJokeComponent}
keyExtractor={(item: CustomJoke) => item.id.toString()} keyExtractor={(item: CustomJoke) => item.id.toString()}
/> />
@ -42,10 +49,9 @@ export function AccueilScreen() {
<Image source={require("../assets/fire_icon.png")}/> <Image source={require("../assets/fire_icon.png")}/>
</View> </View>
<FlatList showsHorizontalScrollIndicator={false} horizontal={true} <FlatList showsHorizontalScrollIndicator={false} horizontal={true}
data={FiltereData} data={DataCate}
renderItem={ListAllCategories} renderItem={ListAllCategories}
keyExtractor={(item) => item.toString()} keyExtractor={(item : Categorie) => item.name}/>
/>
</SafeAreaView> </SafeAreaView>
); );
} }
@ -88,4 +94,4 @@ categories: {
} }
}); });

@ -1,20 +1,22 @@
import {FlatList, SafeAreaView, StyleSheet, Text, View} from "react-native"; import {FlatList, SafeAreaView, StyleSheet, Text, View} from "react-native";
import React from "react"; import React, {useEffect} from "react";
import {JokeListItems} from "../components/ListeJokeComponent"; import {JokeListItems} from "../components/ListeJokeComponent";
import {Joke} from "../model/Joke";
import {JokeFactory} from "../model/JokeFactory";
import {JokeStub} from "../model/JokeStub";
import {indigo, purpleColor} from "../Theme"; import {indigo, purpleColor} from "../Theme";
import {CustomJoke} from "../model/CustomJoke"; import {CustomJoke} from "../model/CustomJoke";
import {useDispatch, useSelector} from 'react-redux';
import {getLatestJokes, getSampleJoke, setSample} from "../redux/actions/sampleAction";
const DATACUSTOM = JokeFactory.createCustomJokes(JokeStub.customJokes)
const DATASAMPLE = JokeFactory.createSampleJokes(JokeStub.sampleJokes)
//@ts-ignore
export let DataGen: Joke[] = DATACUSTOM.concat(DATASAMPLE);
export function ListJokeScreen() { export function ListJokeScreen() {
const DataGen = useSelector((state: any) => state.sampleReducer.sampleJoke);
const dispatch = useDispatch();
useEffect(() => {
const getJokes = async () => {
dispatch(setSample(await getSampleJoke()));
};
getJokes();
}, [dispatch]);
return ( return (
<SafeAreaView style={styles.container}> <SafeAreaView style={styles.container}>
<FlatList <FlatList

Loading…
Cancel
Save