From ad0c66c077fbb36d36b768265077b838c0d9d721 Mon Sep 17 00:00:00 2001 From: olewandowski1 Date: Thu, 8 Feb 2024 13:16:56 +0100 Subject: [PATCH] ONI-164: add setting to enable displaying first name before second name --- src/components/UserFilter.js | 127 ++++++++++-------- src/components/UserMasterPanel.js | 66 ++++++--- src/components/UserSearcher.js | 78 ++++++----- .../pickers/EnrolmentOfficerPicker.js | 27 +++- .../SubstitutionEnrolmentOfficerPicker.js | 27 +++- src/components/pickers/UserPicker.js | 23 +++- src/constants.js | 4 + 7 files changed, 221 insertions(+), 131 deletions(-) diff --git a/src/components/UserFilter.js b/src/components/UserFilter.js index 6ab85f6..b852fee 100644 --- a/src/components/UserFilter.js +++ b/src/components/UserFilter.js @@ -13,6 +13,7 @@ import { TextInput, formatMessage, } from "@openimis/fe-core"; +import { DEFAULT } from "../constants"; const styles = (theme) => ({ dialogTitle: theme.dialog.title, @@ -35,7 +36,6 @@ const extractLocations = (locations) => { const village = municipality && locationsArray.find((l) => l.parent && l.parent.id === municipality.id); return { region, district, municipality, village }; - }; const getParentLocation = (locations) => { @@ -71,10 +71,18 @@ const getParentLocation = (locations) => { }; } return newLocation; - }; class UserFilter extends Component { + constructor(props) { + super(props); + this.renderLastNameFirst = props.modulesManager.getConf( + "fe-insuree", + "renderLastNameFirst", + DEFAULT.RENDER_LAST_NAME_FIRST, + ); + } + state = { locationFilters: {}, selectedDistrict: {}, @@ -90,7 +98,6 @@ class UserFilter extends Component { return !!filters && !!filters[k] ? filters[k].value : null; }; - filterTextFieldValue = (k) => { const { filters } = this.props; return !!filters && !!filters[k] ? filters[k].value : ""; @@ -103,7 +110,6 @@ class UserFilter extends Component { return district; }; - onChangeCheckbox = (key, value) => { const filters = [ { @@ -163,8 +169,60 @@ class UserFilter extends Component { onChangeFilters(filters); }; + renderLastNameField = (classes) => ( + + + this.debouncedOnChangeFilter([ + { + id: "lastName", + value: v, + filter: `lastName: "${v}"`, + }, + ]) + } + /> + + } + /> + ); + + renderGivenNameField = (classes) => ( + + + this.debouncedOnChangeFilter([ + { + id: "otherNames", + value: v, + filter: `otherNames: "${v}"`, + }, + ]) + } + /> + + } + /> + ); + render() { - const { classes, filters, onChangeFilters , intl} = this.props; + const { classes, filters, onChangeFilters, intl } = this.props; const { locationFilters, currentUserType, currentUserRoles, selectedDistrict } = this.state; return (
@@ -204,7 +262,6 @@ class UserFilter extends Component { pubRef="location.HealthFacilityPicker" withNull={true} value={this.filterValue("healthFacilityId") || ""} - district={selectedDistrict} onChange={(v) => { onChangeFilters([ @@ -255,52 +312,17 @@ class UserFilter extends Component { } /> - - - this.debouncedOnChangeFilter([ - { - id: "lastName", - value: v, - filter: `lastName: "${v}"`, - }, - ]) - } - /> - - } - /> - - - this.debouncedOnChangeFilter([ - { - id: "otherNames", - value: v, - filter: `otherNames: "${v}"`, - }, - ]) - } - /> - - } - /> + {this.renderLastNameFirst ? ( + <> + {this.renderLastNameField(classes)} + {this.renderGivenNameField(classes)} + + ) : ( + <> + {this.renderGivenNameField(classes)} + {this.renderLastNameField(classes)} + + )} } label={formatMessage(intl, "admin", "UserFilter.showDeleted")} - /> } diff --git a/src/components/UserMasterPanel.js b/src/components/UserMasterPanel.js index 5cb1c25..00c7b3b 100644 --- a/src/components/UserMasterPanel.js +++ b/src/components/UserMasterPanel.js @@ -1,3 +1,4 @@ +/* eslint-disable no-shadow */ import React, { useEffect, useState } from "react"; import { connect, useDispatch } from "react-redux"; @@ -13,7 +14,7 @@ import { PublishedComponent, ValidatedTextInput, } from "@openimis/fe-core"; -import { CLAIM_ADMIN_USER_TYPE, ENROLMENT_OFFICER_USER_TYPE, EMAIL_REGEX_PATTERN } from "../constants"; +import { CLAIM_ADMIN_USER_TYPE, ENROLMENT_OFFICER_USER_TYPE, EMAIL_REGEX_PATTERN, DEFAULT } from "../constants"; import { usernameValidationCheck, usernameValidationClear, @@ -61,6 +62,11 @@ const UserMasterPanel = (props) => { } = props; const { formatMessage } = useTranslations("admin", modulesManager); const dispatch = useDispatch(); + const renderLastNameFirst = modulesManager.getConf( + "fe-insuree", + "renderLastNameFirst", + DEFAULT.RENDER_LAST_NAME_FIRST, + ); const shouldValidateUsername = (inputValue) => { const shouldBeValidated = inputValue !== savedUsername; @@ -91,7 +97,6 @@ const UserMasterPanel = (props) => { handleEmailChange(edited?.email); }, []); - const [showPassword, setShowPassword] = useState(false); const handleClickShowPassword = () => setShowPassword((show) => !show); @@ -111,6 +116,32 @@ const UserMasterPanel = (props) => { onEditedChanged({ ...edited, password: generatedPassword, confirmPassword: generatedPassword }); }; + const renderLastNameField = (edited, classes, readOnly) => ( + + onEditedChanged({ ...edited, lastName })} + /> + + ); + + const renderGivenNameField = (edited, classes, readOnly) => ( + + onEditedChanged({ ...edited, otherNames })} + /> + + ); + return ( @@ -135,26 +166,17 @@ const UserMasterPanel = (props) => { }} /> - - onEditedChanged({ ...edited, otherNames })} - /> - - - onEditedChanged({ ...edited, lastName })} - /> - + {renderLastNameFirst ? ( + <> + {renderLastNameField(edited, classes, readOnly)} + {renderGivenNameField(edited, classes, readOnly)} + + ) : ( + <> + {renderGivenNameField(edited, classes, readOnly)} + {renderLastNameField(edited, classes, readOnly)} + + )} {!( obligatoryUserFields?.email == "H" || (edited.userTypes?.includes(ENROLMENT_OFFICER_USER_TYPE) && obligatoryEOFields?.email == "H") diff --git a/src/components/UserSearcher.js b/src/components/UserSearcher.js index a2c2338..71f75dd 100644 --- a/src/components/UserSearcher.js +++ b/src/components/UserSearcher.js @@ -17,47 +17,56 @@ import { decodeId, } from "@openimis/fe-core"; import { fetchUsersSummaries, deleteUser } from "../actions"; -import { RIGHT_USER_DELETE } from "../constants"; +import { DEFAULT, RIGHT_USER_DELETE } from "../constants"; import UserFilter from "./UserFilter"; const USER_SEARCHER_CONTRIBUTION_KEY = "user.UserSearcher"; -const getHeaders = () => [ - "admin.user.username", - "admin.user.lastName", - "admin.user.otherNames", - "admin.user.email", - "admin.user.phone", - "admin.user.dob", - "", -]; - -const getSorts = () => [ - ["username", true], - ["iUser_LastName", true], - ["iUser_OtherNames", true], - ["iUser_Email", true], - ["iUser_Phone", true], - ["officer__dob", false], -]; - -const getAligns = () => { - const aligns = getHeaders().map(() => null); - aligns.splice(-1, 1, "right"); - return aligns; -}; - const styles = (theme) => ({ horizontalButtonContainer: theme.buttonContainer.horizontal, }); class UserSearcher extends Component { + constructor(props) { + super(props); + this.renderLastNameFirst = props.modulesManager.getConf( + "fe-insuree", + "renderLastNameFirst", + DEFAULT.RENDER_LAST_NAME_FIRST, + ); + } + state = { deleteUser: null, params: {}, defaultParams: {}, }; + getHeaders = () => [ + "admin.user.username", + this.renderLastNameFirst ? "admin.user.lastName" : "admin.user.otherNames", + !this.renderLastNameFirst ? "admin.user.lastName" : "admin.user.otherNames", + "admin.user.email", + "admin.user.phone", + "admin.user.dob", + "", + ]; + + getSorts = () => [ + ["username", true], + this.renderLastNameFirst ? ["iUser_LastName", true] : ["iUser_OtherNames", true], + !this.renderLastNameFirst ? ["iUser_LastName", true] : ["iUser_OtherNames", true], + ["iUser_Email", true], + ["iUser_Phone", true], + ["officer__dob", false], + ]; + + getAligns = () => { + const aligns = this.getHeaders().map(() => null); + aligns.splice(-1, 1, "right"); + return aligns; + }; + fetch = (params) => { this.setState({ params }); if (this.props.fetchedUserLocation) { @@ -128,8 +137,8 @@ class UserSearcher extends Component { itemFormatters = () => { const formatters = [ (u) => u.username, - (u) => this.getUserItem(u, "lastName"), - (u) => this.getUserItem(u, "otherNames"), + (u) => (this.renderLastNameFirst ? this.getUserItem(u, "lastName") : this.getUserItem(u, "otherNames")), + (u) => (!this.renderLastNameFirst ? this.getUserItem(u, "lastName") : this.getUserItem(u, "otherNames")), (u) => this.getUserItem(u, "email") || this.getUserItem(u, "emailId"), (u) => this.getUserItem(u, "phone"), (u) => @@ -145,15 +154,11 @@ class UserSearcher extends Component { {this.props.rights.includes(RIGHT_USER_DELETE) && u.validityTo ? null : ( - this.setState({ deleteUser: u })} - disabled={u.validityTo} - > + this.setState({ deleteUser: u })} disabled={u.validityTo}> )} - ), ]; @@ -187,16 +192,15 @@ class UserSearcher extends Component { contributionKey={USER_SEARCHER_CONTRIBUTION_KEY} tableTitle={formatMessageWithValues(intl, "admin.user", "userSummaries", { count: usersPageInfo.totalCount?.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,"), - })} fetch={this.fetch} rowIdentifier={(r) => r.uuid} filtersToQueryParams={this.filtersToQueryParams} defaultOrderBy="-username" - headers={getHeaders} - aligns={getAligns} + headers={this.getHeaders} + aligns={this.getAligns} itemFormatters={this.itemFormatters} - sorts={getSorts} + sorts={this.getSorts} rowDisabled={(_, i) => i.validityTo || i.clientMutationId} rowLocked={(_, i) => i.clientMutationId} onDoubleClick={onDoubleClick} diff --git a/src/components/pickers/EnrolmentOfficerPicker.js b/src/components/pickers/EnrolmentOfficerPicker.js index dd25a8a..5d484e2 100644 --- a/src/components/pickers/EnrolmentOfficerPicker.js +++ b/src/components/pickers/EnrolmentOfficerPicker.js @@ -1,12 +1,8 @@ import React, { useEffect, useState } from "react"; import { useDispatch, useSelector } from "react-redux"; -import { Autocomplete } from "@openimis/fe-core"; +import { Autocomplete, withModulesManager } from "@openimis/fe-core"; import { fetchEnrolmentOfficers } from "../../actions"; - -const formatSuggestion = (p) => { - if (!p) return "?"; - return [p.code, p.lastName, p.otherNames].filter(Boolean).join(" "); -}; +import { DEFAULT } from "../../constants"; const EnrolmentOfficerPicker = (props) => { const { @@ -37,6 +33,23 @@ const EnrolmentOfficerPicker = (props) => { ); }, [searchString]); + const formatSuggestion = (p) => { + const renderLastNameFirst = modulesManager.getConf( + "fe-insuree", + "renderLastNameFirst", + DEFAULT.RENDER_LAST_NAME_FIRST, + ); + + if (!p) return "?"; + return [ + p.username, + renderLastNameFirst ? p.lastName : p.otherNames, + !renderLastNameFirst ? p.lastName : p.otherNames, + ] + .filter(Boolean) + .join(" "); + }; + return ( { ); }; -export default EnrolmentOfficerPicker; +export default withModulesManager(EnrolmentOfficerPicker); diff --git a/src/components/pickers/SubstitutionEnrolmentOfficerPicker.js b/src/components/pickers/SubstitutionEnrolmentOfficerPicker.js index 8d8fc7a..47a6838 100644 --- a/src/components/pickers/SubstitutionEnrolmentOfficerPicker.js +++ b/src/components/pickers/SubstitutionEnrolmentOfficerPicker.js @@ -3,13 +3,9 @@ import { useDispatch, useSelector } from "react-redux"; import { TextField } from "@material-ui/core"; -import { Autocomplete, useTranslations } from "@openimis/fe-core"; +import { withModulesManager, Autocomplete, useTranslations } from "@openimis/fe-core"; import { fetchSubstitutionEOs } from "../../utils"; - -const formatSuggestion = (p) => { - if (!p) return "?"; - return [p.code, p.lastName, p.otherNames].filter(Boolean).join(" "); -}; +import { DEFAULT } from "../../constants"; const SubstitutionEnrolmentOfficerPicker = (props) => { const { @@ -38,6 +34,23 @@ const SubstitutionEnrolmentOfficerPicker = (props) => { fetchSubstitutionEOs(dispatch, modulesManager, officerUuid, searchString, villages); }; + const formatSuggestion = (p) => { + const renderLastNameFirst = modulesManager.getConf( + "fe-insuree", + "renderLastNameFirst", + DEFAULT.RENDER_LAST_NAME_FIRST, + ); + + if (!p) return "?"; + return [ + p.username, + renderLastNameFirst ? p.lastName : p.otherNames, + !renderLastNameFirst ? p.lastName : p.otherNames, + ] + .filter(Boolean) + .join(" "); + }; + return ( { ); }; -export default SubstitutionEnrolmentOfficerPicker; +export default withModulesManager(SubstitutionEnrolmentOfficerPicker); diff --git a/src/components/pickers/UserPicker.js b/src/components/pickers/UserPicker.js index 8b07073..28b5174 100644 --- a/src/components/pickers/UserPicker.js +++ b/src/components/pickers/UserPicker.js @@ -5,6 +5,7 @@ import { Autocomplete } from "@material-ui/lab"; import { TextField } from "@material-ui/core"; import { withModulesManager, useDebounceCb, useTranslations } from "@openimis/fe-core"; import { fetchUsers } from "../../actions"; +import { DEFAULT } from "../../constants"; const styles = (theme) => ({ label: { @@ -12,11 +13,6 @@ const styles = (theme) => ({ }, }); -const formatSuggestion = (p) => { - if (!p) return "?"; - return [p.username, p.iUser?.lastName, p.iUser?.otherNames].filter(Boolean).join(" "); -}; - const UserPicker = (props) => { const { onChange, @@ -48,6 +44,23 @@ const UserPicker = (props) => { if (!multiple) setOpen(false); }; + const formatSuggestion = (p) => { + const renderLastNameFirst = modulesManager.getConf( + "fe-insuree", + "renderLastNameFirst", + DEFAULT.RENDER_LAST_NAME_FIRST, + ); + + if (!p) return "?"; + return [ + p.username, + renderLastNameFirst ? p.iUser?.lastName : p.iUser?.otherNames, + !renderLastNameFirst ? p.iUser?.lastName : p.iUser?.otherNames, + ] + .filter(Boolean) + .join(" "); + }; + useEffect(() => { if (searchString?.length > minCharLookup) { dispatch( diff --git a/src/constants.js b/src/constants.js index 47d66b4..1203861 100644 --- a/src/constants.js +++ b/src/constants.js @@ -22,6 +22,10 @@ export const CLAIM_ADMIN_USER_TYPE = "CLAIM_ADMIN"; export const CLAIM_ADMIN_IS_SYSTEM = 256; export const MODULE_NAME = "user"; +export const DEFAULT = { + RENDER_LAST_NAME_FIRST: true, +}; + // https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address export const EMAIL_REGEX_PATTERN = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;