@fto-consult/expo-ui
Version:
Bibliothèque de composants UI Expo,react-native
212 lines (208 loc) • 10.2 kB
JavaScript
import {defaultStr,defaultVal,isNonNullString,defaultNumber,extendObj,defaultObj} from "$cutils";
import React from "$react";
import CountUp from "$ecomponents/CountUp";
import Avatar from "$ecomponents/Avatar";
import { Pressable } from "react-native";
import {ActivityIndicator} from "react-native-paper";
import Item from "$ecomponents/Expandable/Item";
import {navigateToTableDataList} from "$enavigation/utils";
import theme from "$theme";
import Label from "$ecomponents/Label";
import PropTypes from "prop-types";
import APP from "$capp/instance"
import cActions from "$cactions";
import {View} from "react-native";
import {Menu} from "$ecomponents/BottomSheet";
import Dashboard from "$ecomponents/Datagrid/Dashboard";
import Icon from "$ecomponents/Icon";
export default function DatabaseStatisticContainer ({dashboardProps,fields,onRefreshAll,fetchDataProps,table,fetchCount,index,testID,title,icon,onPress:customOnPress,columns,fetchData,withDashboard,...props}){
dashboardProps = defaultObj(dashboardProps);
const [count,setCount] = React.useState(0);
const datagridRef = React.useRef(null);
let {} = props;
table = defaultObj(table);
const databaseStatisticsFields = defaultObj(fields,columns,table.databaseStatisticsFields);
const hasDFields = table.databaseStatistics !== false && Object.size(databaseStatisticsFields,true);
if(!withDashboard && hasDFields){
withDashboard = true;
}
if(typeof fetchData !=='function'){
fetchData = undefined;
}
withDashboard = withDashboard && typeof fetchData == 'function'? true : false;
columns = Object.size(columns,true)? columns : Object.size(databaseStatisticsFields,true)? databaseStatisticsFields : table.fields;
const tableName = defaultStr(table.tableName,table.table).toUpperCase();
fetchCount = typeof table.fetchCount =='function'? table.fetchCount : typeof fetchCount =='function'? fetchCount : undefined;
if((!fetchCount && !withDashboard) || !tableName) {
return null
}
const refreshingRef = React.useRef(null);
const isMounted = React.useIsMounted();
const onRefreshAllItem = typeof onRefreshAll =='function'? {
text : "Tout actualiser",
onPress : onRefreshAll,
icon : "refresh-circle"
} : {}
const [isLoading,setIsLoading] = React.useState(withDashboard?false:true);
const refresh = ()=>{
if(refreshingRef.current || !isMounted()) return;
if(!fetchCount){
return;
}
refreshingRef.current = true;
setIsLoading(true);
setTimeout(()=>{
fetchCount({table,tableName}).then((count)=>{
setCount(count);
setIsLoading(false);
refreshingRef.current = false;
}).catch((e)=>{
setIsLoading(false);
refreshingRef.current = false;
});
},100);
}
React.useEffect(()=>{
if(!withDashboard){
APP.on(cActions.upsert(tableName),refresh);
APP.on(cActions.remove(tableName),refresh);
refresh();
}
return ()=>{
if(!withDashboard){
APP.off(cActions.upsert(tableName),refresh);
APP.off(cActions.remove(tableName),refresh);
}
}
},[]);
const progressBar = <View style={[theme.styles.justifyContentFlexStart,theme.styles.p1,theme.styles.alignItemsFlexStart]}>
<ActivityIndicator color={theme.colors.primary}/>
</View>;
const isDatagridLoading = datagridRef.current && datagridRef.current.isLoading && datagridRef.current.isLoading();
testID = defaultStr(testID,"RN_DatabaseStatistic_"+table);
const onPress = (args)=>{
if(customOnPress && customOnPress(args) === false) return;
navigateToTableDataList(tableName,{
tableName
})
};
const fetchFields = React.useMemo(()=>{
const fetchFields = [];
Object.map(columns,(field,f)=>{
const ff = defaultStr(isObj(field) && field.filter !== false? field.field: undefined,f);
if(ff){
fetchFields.push(ff);
}
});
return fetchFields;
},[columns]);
const counUpStyle = {fontSize:20,fontWeight:'bold',color:theme.colors.secondaryOnSurface};
title = defaultVal(title,table.label,table.text);
icon = defaultVal(icon,table.icon);
title = React.isValidElement(title,true)?<Label splitText numberOfLines={1} color={theme.colors.primaryOnSurface} style={[{fontSize:15}]}>{title}</Label>: null;
const titleText = title && React.getTextContent(title) || null;
const titleItem = titleText && {text:titleText,icon,divider:true} || null;
return withDashboard ? <Dashboard
chartProps = {{
stroke: {
curve: 'straight'
},
fill: {
type: 'solid',
opacity: 1,
},
}}
sessionName = {tableName+"-database-statistics"}
{...props}
style = {[theme.styles.pr1,props.style]}
columns = {columns}
ref = {datagridRef}
progressBar = {isLoading?<View/>:<View style={[theme.styles.w100,theme.styles.alignItemsCenter,theme.styles.justifyContentCenter]}>{progressBar}</View>}
tableName = {tableName}
table = {table}
fetchData = {(options)=>{
return fetchData({...defaultObj(fetchDataProps),fields:fetchFields,table,tableName,...options});
}}
title = {({context,config:chartConfig})=>{
if(!context || !context.state) return null;
const {state} = context;
//const footers = context.getFooters && context.getFooters() || {};
const dataSize = context.getStateDataSize && context.getStateDataSize() || 0;
const footersValues = context.getFooterValues && context.getFooterValues() || {};
const config = Object.assign({},chartConfig,(typeof context.getConfig =="function"? context.getConfig() : state.config));
const y = defaultStr(config.y);
const footerValue = y && isObj(footersValues) && footersValues[y] || null;
const format = defaultStr(isObj(footerValue) && isNonNullString(footerValue.format) && footerValue.format || undefined).toLowerCase();
const aggregatorFunction = isNonNullString(state.aggregatorFunction)? state.aggregatorFunction : undefined;
let value = isObj(footerValue) && aggregatorFunction && aggregatorFunction in footerValue ? footerValue[aggregatorFunction] : undefined;
if(typeof value !=='number'){
value = isObj(footerValue) && typeof footerValue.sum =='number'? footerValue.sum : 0;
}
const formattedValue = typeof context.formatValue =="function"? context.formatValue(value,format) : (format =='money'?value.formatMoney():value.formatNumber());
return <Pressable onPress={onPress} testID={testID+"_TitleContainer"} style={[theme.styles.w100]}>
<View testID={testID+"_TitleCountUp"} style={[theme.styles.w100]}>
<View style={[theme.styles.w100,theme.styles.row,theme.styles.alignItemsCenter]}>
<Icon style={[theme.styles.noPadding,theme.styles.noMargin]} suffix={index} icon= {icon} size={20} label={title}/>
{title}
{typeof dataSize =='number' && dataSize && <Label>
{dataSize.formatNumber()}
</Label> || null}
</View>
<Menu
testID={testID+"_Menu"}
items = {[titleItem,...context.renderMenu(),onRefreshAllItem]}
anchor = {(p)=><Pressable {...p} style={[theme.styles.pl1]} testID={testID+"_MenuAnchor"}>
<Label
textCenter
style = {counUpStyle}
>{formattedValue}</Label>
</Pressable>}
/>
</View>
</Pressable>
}}
/> : <Item
onPress = {onPress}
title = {title}
//style = {[theme.styles.pv1]}
description = {isLoading ?progressBar:<CountUp
from={0}
to={count}
style = {counUpStyle}
/>}
titleProps ={{primary : true}}
left = {(aProps)=>{
return <Menu
testID={testID+"_Menu"}
items = {[
titleItem,
{
icon : "refresh",
onPress : refresh,
text : "Actualiser"
},
onRefreshAllItem,
]}
anchor = {(p)=><Avatar suffix={index} {...aProps} {...p} icon= {icon} size={40} label={title}/>}
/>
}}
/>;
}
/*** DBSTAT, prend en paramètre le nom de la bd ainsi que celui de la table et affiche en statistic,:
* Le nombre d'éléments crées en bases ainsi que ceux actifs
*/
DatabaseStatisticContainer.propTypes = {
...Item.propTypes,
/*** les props supplémentaires à passer à la fonction fetchData */
fetchDataProps : PropTypes.oneOfType([
PropTypes.object,
]),
/*** La méthode fetchCount doit retourner une promèsse qui lorsqu'elle est résolue, résoue le nombre d'éléments de la table de données en bd */
fetchCount : PropTypes.func,//la fonction permettant de counter les éléments de la table data
table : PropTypes.shape({
table : PropTypes.string,
tableName : PropTypes.string,
fetchCount : PropTypes.func,//la fonction permettant de counter les éléments de la table data
}).isRequired,
title : PropTypes.string, //le titre à afficher
}