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

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

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

@ -12,12 +12,15 @@
"@react-navigation/bottom-tabs": "^6.5.11",
"@react-navigation/native": "^6.1.9",
"@react-navigation/stack": "^6.3.20",
"@reduxjs/toolkit": "^2.2.1",
"@types/react": "~18.2.45",
"expo": "~50.0.3",
"expo-status-bar": "~1.11.1",
"react": "18.2.0",
"react-native": "0.73.2",
"react-native-gesture-handler": "^2.15.0",
"react-redux": "^9.1.0",
"redux": "^5.0.1",
"typescript": "^5.3.0"
},
"devDependencies": {
@ -6244,6 +6247,29 @@
"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": {
"version": "2.0.0",
"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",
"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": {
"version": "17.0.32",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz",
@ -8839,6 +8870,15 @@
"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": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
@ -12062,6 +12102,32 @@
"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": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz",
@ -12123,6 +12189,19 @@
"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": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@ -12234,6 +12313,11 @@
"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": {
"version": "1.22.8",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
@ -13361,6 +13445,14 @@
"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": {
"version": "1.0.2",
"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/native": "^6.1.9",
"@react-navigation/stack": "^6.3.20",
"@reduxjs/toolkit": "^2.2.1",
"@types/react": "~18.2.45",
"expo": "~50.0.3",
"expo-status-bar": "~1.11.1",
"react": "18.2.0",
"react-native": "0.73.2",
"react-native-gesture-handler": "^2.15.0",
"react-redux": "^9.1.0",
"redux": "^5.0.1",
"typescript": "^5.3.0"
},
"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 {indigo, purpleColor} from "../Theme";
import {Joke} from "../model/Joke";
import {DataGen, ListJokeScreen} from "./ListJokeScreen";
import React from "react";
import React, {useEffect} from "react";
import {HorizontalListJokeComponent} from "../components/HorizontalListJokeComponent";
import {ListAllCategories} from "../components/ListAllCategories";
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() {
// Permet de filtrer les types des blagues pour les afficher dans la liste des categories
const FiltereData = filterCategory(LastJokes);
const DataGen = useSelector((state: any) => state.sampleReducer.recentJokes);
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 (
<SafeAreaView style={styles.container}>
@ -33,7 +40,7 @@ export function AccueilScreen() {
<Text style={styles.titleAccueil}>Dernieres Blagues</Text>
</View>
<FlatList showsHorizontalScrollIndicator={false} horizontal={true}
data={LastJokes}
data={DataGen}
renderItem={HorizontalListJokeComponent}
keyExtractor={(item: CustomJoke) => item.id.toString()}
/>
@ -42,10 +49,9 @@ export function AccueilScreen() {
<Image source={require("../assets/fire_icon.png")}/>
</View>
<FlatList showsHorizontalScrollIndicator={false} horizontal={true}
data={FiltereData}
data={DataCate}
renderItem={ListAllCategories}
keyExtractor={(item) => item.toString()}
/>
keyExtractor={(item : Categorie) => item.name}/>
</SafeAreaView>
);
}

@ -1,20 +1,22 @@
import {FlatList, SafeAreaView, StyleSheet, Text, View} from "react-native";
import React from "react";
import React, {useEffect} from "react";
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 {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() {
const DataGen = useSelector((state: any) => state.sampleReducer.sampleJoke);
const dispatch = useDispatch();
useEffect(() => {
const getJokes = async () => {
dispatch(setSample(await getSampleJoke()));
};
getJokes();
}, [dispatch]);
return (
<SafeAreaView style={styles.container}>
<FlatList

Loading…
Cancel
Save