258 lines
6.6 KiB
TypeScript
258 lines
6.6 KiB
TypeScript
/*
|
|
* Copyright (c) 2019 - 2020 Arnaud Vergnet.
|
|
*
|
|
* This file is part of Campus INSAT.
|
|
*
|
|
* Campus INSAT is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Campus INSAT is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
import * as React from 'react';
|
|
import i18n from 'i18n-js';
|
|
import { List, useTheme, withTheme } from 'react-native-paper';
|
|
import WebSectionList from '../../../components/Screens/WebSectionList';
|
|
import MaterialHeaderButtons, {
|
|
Item,
|
|
} from '../../../components/Overrides/CustomHeaderButton';
|
|
import type { SectionListDataType } from '../../../components/Screens/WebSectionList';
|
|
import { Image, StyleSheet } from 'react-native';
|
|
import Urls from '../../../constants/Urls';
|
|
import { readData } from '../../../utils/WebData';
|
|
import { useNavigation } from '@react-navigation/core';
|
|
import { useLayoutEffect } from 'react';
|
|
import { useCachedProximoCategories } from '../../../context/cacheContext';
|
|
import GENERAL_STYLES from '../../../constants/Styles';
|
|
|
|
const LIST_ITEM_HEIGHT = 84;
|
|
|
|
export type ProximoCategoryType = {
|
|
id: number;
|
|
name: string;
|
|
icon: string;
|
|
created_at: string;
|
|
updated_at: string;
|
|
nb_articles: number;
|
|
};
|
|
|
|
export type ProximoArticleType = {
|
|
id: number;
|
|
name: string;
|
|
description: string;
|
|
quantity: number;
|
|
price: number;
|
|
code: string;
|
|
image: string;
|
|
category_id: number;
|
|
created_at: string;
|
|
updated_at: string;
|
|
category: ProximoCategoryType;
|
|
};
|
|
|
|
export type CategoriesType = Array<ProximoCategoryType>;
|
|
|
|
const styles = StyleSheet.create({
|
|
item: {
|
|
justifyContent: 'center',
|
|
},
|
|
avatar: {
|
|
marginLeft: 5,
|
|
...GENERAL_STYLES.centerVertical,
|
|
height: 35,
|
|
width: 35,
|
|
},
|
|
});
|
|
|
|
function sortCategories(
|
|
a: ProximoCategoryType,
|
|
b: ProximoCategoryType
|
|
): number {
|
|
const str1 = a.name.toLowerCase();
|
|
const str2 = b.name.toLowerCase();
|
|
|
|
// Make 'All' category with id -1 stick to the top
|
|
if (a.id === -1) {
|
|
return -1;
|
|
}
|
|
if (b.id === -1) {
|
|
return 1;
|
|
}
|
|
|
|
// Sort others by name ascending
|
|
if (str1 < str2) {
|
|
return -1;
|
|
}
|
|
if (str1 > str2) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Class defining the main proximo screen.
|
|
* This screen shows the different categories of articles offered by proximo.
|
|
*/
|
|
function ProximoMainScreen() {
|
|
const navigation = useNavigation();
|
|
const theme = useTheme();
|
|
const { categories, setCategories } = useCachedProximoCategories();
|
|
|
|
useLayoutEffect(() => {
|
|
navigation.setOptions({
|
|
headerRight: () => getHeaderButtons(),
|
|
});
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [navigation]);
|
|
|
|
/**
|
|
* Callback used when the search button is pressed.
|
|
* This will open a new ProximoListScreen with all items displayed
|
|
*/
|
|
const onPressSearchBtn = () => {
|
|
const searchScreenData = {
|
|
shouldFocusSearchBar: true,
|
|
category: -1,
|
|
};
|
|
navigation.navigate('proximo-list', searchScreenData);
|
|
};
|
|
|
|
const onPressAboutBtn = () => navigation.navigate('proximo-about');
|
|
|
|
const getHeaderButtons = () => {
|
|
return (
|
|
<MaterialHeaderButtons>
|
|
<Item
|
|
title={'magnify'}
|
|
iconName={'magnify'}
|
|
onPress={onPressSearchBtn}
|
|
/>
|
|
<Item
|
|
title={'information'}
|
|
iconName={'information'}
|
|
onPress={onPressAboutBtn}
|
|
/>
|
|
</MaterialHeaderButtons>
|
|
);
|
|
};
|
|
|
|
/**
|
|
* Extracts a key for the given category
|
|
*
|
|
* @param item The category to extract the key from
|
|
* @return {*} The extracted key
|
|
*/
|
|
const getKeyExtractor = (item: ProximoCategoryType): string =>
|
|
item.id.toString();
|
|
|
|
/**
|
|
* Gets the given category render item
|
|
*
|
|
* @param item The category to render
|
|
* @return {*}
|
|
*/
|
|
const getRenderItem = ({ item }: { item: ProximoCategoryType }) => {
|
|
const dataToSend = {
|
|
shouldFocusSearchBar: false,
|
|
category: item.id,
|
|
};
|
|
const article_number = item.nb_articles;
|
|
const subtitle = `${article_number} ${
|
|
article_number > 1
|
|
? i18n.t('screens.proximo.articles')
|
|
: i18n.t('screens.proximo.article')
|
|
}`;
|
|
const onPress = () => navigation.navigate('proximo-list', dataToSend);
|
|
if (article_number > 0) {
|
|
return (
|
|
<List.Item
|
|
title={item.name}
|
|
description={subtitle}
|
|
onPress={onPress}
|
|
left={(props) =>
|
|
item.icon.endsWith('.png') ? (
|
|
<Image
|
|
style={{ ...props.style, ...styles.avatar }}
|
|
source={{ uri: Urls.proximo.icons + item.icon }}
|
|
/>
|
|
) : (
|
|
<List.Icon
|
|
style={props.style}
|
|
icon={item.icon}
|
|
color={theme.colors.primary}
|
|
/>
|
|
)
|
|
}
|
|
right={(props) => (
|
|
<List.Icon
|
|
color={props.color}
|
|
style={props.style}
|
|
icon={'chevron-right'}
|
|
/>
|
|
)}
|
|
style={{
|
|
height: LIST_ITEM_HEIGHT,
|
|
...styles.item,
|
|
}}
|
|
/>
|
|
);
|
|
}
|
|
return null;
|
|
};
|
|
|
|
/**
|
|
* Creates the dataset to be used in the FlatList
|
|
*
|
|
* @param fetchedData
|
|
* @return {*}
|
|
* */
|
|
const createDataset = (
|
|
data: CategoriesType | undefined
|
|
): SectionListDataType<ProximoCategoryType> => {
|
|
if (data) {
|
|
let totalArticles = 0;
|
|
data.forEach((c) => (totalArticles += c.nb_articles));
|
|
const finalData: CategoriesType = [
|
|
{
|
|
id: -1,
|
|
name: i18n.t('screens.proximo.all'),
|
|
icon: 'star',
|
|
created_at: '',
|
|
updated_at: '',
|
|
nb_articles: totalArticles,
|
|
},
|
|
...data,
|
|
];
|
|
return [
|
|
{
|
|
title: '',
|
|
data: finalData.filter((c) => c.nb_articles > 0).sort(sortCategories),
|
|
keyExtractor: getKeyExtractor,
|
|
},
|
|
];
|
|
} else {
|
|
return [];
|
|
}
|
|
};
|
|
|
|
return (
|
|
<WebSectionList
|
|
request={() => readData<CategoriesType>(Urls.proximo.categories)}
|
|
createDataset={createDataset}
|
|
refreshOnFocus={true}
|
|
renderItem={getRenderItem}
|
|
cache={categories}
|
|
onCacheUpdate={setCategories}
|
|
/>
|
|
);
|
|
}
|
|
|
|
export default withTheme(ProximoMainScreen);
|