@palladium-ethiopia/esm-admin-app 5.4.2-pre.100

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/.turbo/turbo-build.log +15 -0
  2. package/README.md +12 -0
  3. package/dist/117.js +1 -0
  4. package/dist/152.js +1 -0
  5. package/dist/152.js.map +1 -0
  6. package/dist/209.js +1 -0
  7. package/dist/209.js.map +1 -0
  8. package/dist/41.js +1 -0
  9. package/dist/41.js.map +1 -0
  10. package/dist/442.js +1 -0
  11. package/dist/442.js.map +1 -0
  12. package/dist/466.js +1 -0
  13. package/dist/466.js.map +1 -0
  14. package/dist/555.js +1 -0
  15. package/dist/555.js.map +1 -0
  16. package/dist/61.js +1 -0
  17. package/dist/61.js.map +1 -0
  18. package/dist/672.js +15 -0
  19. package/dist/672.js.map +1 -0
  20. package/dist/689.js +1 -0
  21. package/dist/689.js.map +1 -0
  22. package/dist/710.js +1 -0
  23. package/dist/710.js.map +1 -0
  24. package/dist/712.js +1 -0
  25. package/dist/712.js.map +1 -0
  26. package/dist/771.js +1 -0
  27. package/dist/771.js.map +1 -0
  28. package/dist/789.js +1 -0
  29. package/dist/789.js.map +1 -0
  30. package/dist/806.js +1 -0
  31. package/dist/826.js +1 -0
  32. package/dist/826.js.map +1 -0
  33. package/dist/914.js +27 -0
  34. package/dist/914.js.map +1 -0
  35. package/dist/926.js +17 -0
  36. package/dist/926.js.map +1 -0
  37. package/dist/ethiopia-esm-admin-app.js +6 -0
  38. package/dist/ethiopia-esm-admin-app.js.buildmanifest.json +556 -0
  39. package/dist/ethiopia-esm-admin-app.js.map +1 -0
  40. package/dist/main.js +32 -0
  41. package/dist/main.js.map +1 -0
  42. package/dist/routes.json +1 -0
  43. package/jest.config.js +8 -0
  44. package/package.json +52 -0
  45. package/rspack.config.js +1 -0
  46. package/src/components/confirm-modal/confirmation-operation-modal.component.tsx +43 -0
  47. package/src/components/confirm-modal/confirmation-operation.test.tsx +69 -0
  48. package/src/components/dashboard/dashboard.component.tsx +131 -0
  49. package/src/components/dashboard/dashboard.scss +38 -0
  50. package/src/components/dashboard/etl-dashboard.component.tsx +11 -0
  51. package/src/components/empty-state/empty-state-log.components.tsx +20 -0
  52. package/src/components/empty-state/empty-state-log.scss +28 -0
  53. package/src/components/empty-state/empty-state-log.test.tsx +24 -0
  54. package/src/components/facility-setup/card.component.tsx +16 -0
  55. package/src/components/facility-setup/facility-info.component.tsx +142 -0
  56. package/src/components/facility-setup/facility-info.scss +87 -0
  57. package/src/components/facility-setup/facility-setup.component.tsx +21 -0
  58. package/src/components/facility-setup/facility-setup.resource.tsx +7 -0
  59. package/src/components/facility-setup/facility-setup.scss +38 -0
  60. package/src/components/facility-setup/header/header.component.tsx +23 -0
  61. package/src/components/facility-setup/header/header.scss +19 -0
  62. package/src/components/header/header-illustration.component.tsx +13 -0
  63. package/src/components/header/header.component.tsx +28 -0
  64. package/src/components/header/header.scss +19 -0
  65. package/src/components/hook/healthWorkerAdapter.ts +213 -0
  66. package/src/components/hook/useFacilityInfo.tsx +37 -0
  67. package/src/components/hook/useSystemRoleSetting.tsx +33 -0
  68. package/src/components/locations/auto-suggest/autosuggest.component.tsx +149 -0
  69. package/src/components/locations/auto-suggest/autosuggest.scss +61 -0
  70. package/src/components/locations/auto-suggest/location-autosuggest.component.tsx +94 -0
  71. package/src/components/locations/auto-suggest/location-autosuggest.scss +48 -0
  72. package/src/components/locations/common/results-tile.component.tsx +45 -0
  73. package/src/components/locations/common/results-tile.scss +86 -0
  74. package/src/components/locations/forms/add-location/add-location.workspace.scss +34 -0
  75. package/src/components/locations/forms/add-location/add-location.workspace.tsx +200 -0
  76. package/src/components/locations/forms/search-location/search-location.workspace.scss +79 -0
  77. package/src/components/locations/forms/search-location/search-location.workspace.tsx +215 -0
  78. package/src/components/locations/header/header.component.tsx +48 -0
  79. package/src/components/locations/header/header.scss +58 -0
  80. package/src/components/locations/helpers/index.ts +16 -0
  81. package/src/components/locations/home/home-locations.component.tsx +18 -0
  82. package/src/components/locations/home/home-locations.scss +8 -0
  83. package/src/components/locations/hooks/UseFacilityLocations.ts +12 -0
  84. package/src/components/locations/hooks/useLocation.ts +18 -0
  85. package/src/components/locations/hooks/useLocationTags.ts +15 -0
  86. package/src/components/locations/tables/locations-table.component.tsx +243 -0
  87. package/src/components/locations/tables/locations-table.resource.ts +26 -0
  88. package/src/components/locations/tables/locations-table.scss +115 -0
  89. package/src/components/locations/types/index.ts +120 -0
  90. package/src/components/locations/utils/index.ts +5 -0
  91. package/src/components/logs-table/operation-log-resource.ts +41 -0
  92. package/src/components/logs-table/operation-log-table.component.tsx +120 -0
  93. package/src/components/logs-table/operation-log.scss +10 -0
  94. package/src/components/logs-table/operation-log.test.tsx +47 -0
  95. package/src/components/modal/hwr-confirmation.modal.scss +21 -0
  96. package/src/components/modal/hwr-confirmation.modal.tsx +170 -0
  97. package/src/components/modal/hwr-empty.modal.component.tsx +54 -0
  98. package/src/components/modal/hwr-sync.modal.scss +30 -0
  99. package/src/components/modal/hwr-sync.modal.tsx +209 -0
  100. package/src/components/modal/hwr-sync.resource.ts +23 -0
  101. package/src/components/provider-banner/provider-banner.component.tsx +106 -0
  102. package/src/components/provider-banner/provider-banner.module.scss +51 -0
  103. package/src/components/provider-banner/provider-banner.resource.ts +29 -0
  104. package/src/components/side-menu/left-panel.scss +42 -0
  105. package/src/components/side-menu/left-pannel.component.tsx +22 -0
  106. package/src/components/users/header/header.scss +90 -0
  107. package/src/components/users/header/user-management-header.component.tsx +42 -0
  108. package/src/components/users/manage-users/hooks/useProviderAttributeMapping.ts +110 -0
  109. package/src/components/users/manage-users/hooks/useUserFormSteps.ts +119 -0
  110. package/src/components/users/manage-users/hooks/useUserFormSubmission.ts +264 -0
  111. package/src/components/users/manage-users/hooks/useUserManagementForm.ts +122 -0
  112. package/src/components/users/manage-users/manage-user-role-scope/user-role-scope-list/user-role-scope-list.component.tsx +177 -0
  113. package/src/components/users/manage-users/manage-user-role-scope/user-role-scope-workspace/user-role-fields.scss +117 -0
  114. package/src/components/users/manage-users/manage-user-role-scope/user-role-scope-workspace/user-role-scope-fields.component.tsx +290 -0
  115. package/src/components/users/manage-users/manage-user-role-scope/user-role-scope-workspace/user-role-scope.workspace.tsx +316 -0
  116. package/src/components/users/manage-users/manage-user-role-scope/user-role-scope-workspace/userRoleScopeFormSchema.tsx +43 -0
  117. package/src/components/users/manage-users/manage-user.component.tsx +19 -0
  118. package/src/components/users/manage-users/manage-user.scss +31 -0
  119. package/src/components/users/manage-users/provider-autosuggest.component.tsx +117 -0
  120. package/src/components/users/manage-users/provider-search.resource.ts +34 -0
  121. package/src/components/users/manage-users/sections/demographic-section.component.tsx +156 -0
  122. package/src/components/users/manage-users/sections/login-section.component.tsx +88 -0
  123. package/src/components/users/manage-users/sections/provider-section.component.tsx +270 -0
  124. package/src/components/users/manage-users/sections/roles-section.component.tsx +88 -0
  125. package/src/components/users/manage-users/user-details/user-detail.scss +75 -0
  126. package/src/components/users/manage-users/user-details/user-details.component.tsx +182 -0
  127. package/src/components/users/manage-users/user-list/user-list.component.tsx +378 -0
  128. package/src/components/users/manage-users/user-list/user-list.resource.ts +30 -0
  129. package/src/components/users/manage-users/user-list/user-list.scss +37 -0
  130. package/src/components/users/manage-users/user-management.constants.ts +20 -0
  131. package/src/components/users/manage-users/user-management.utils.ts +100 -0
  132. package/src/components/users/manage-users/user-management.workspace.scss +172 -0
  133. package/src/components/users/manage-users/user-management.workspace.tsx +334 -0
  134. package/src/components/users/userManagementFormSchema.tsx +179 -0
  135. package/src/config-schema.ts +142 -0
  136. package/src/constants.ts +50 -0
  137. package/src/declarations.d.ts +2 -0
  138. package/src/index.ts +55 -0
  139. package/src/left-pannel-link.component.tsx +40 -0
  140. package/src/root.component.tsx +39 -0
  141. package/src/root.scss +12 -0
  142. package/src/routes.json +100 -0
  143. package/src/setup-tests.ts +1 -0
  144. package/src/types/index.ts +385 -0
  145. package/src/user-management.resources.ts +232 -0
  146. package/src/utils/utils.ts +20 -0
  147. package/translations/am.json +159 -0
  148. package/translations/en.json +159 -0
  149. package/tsconfig.json +5 -0
@@ -0,0 +1,177 @@
1
+ import React, { useCallback, useMemo, useState } from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import { CardHeader, EmptyState } from '@openmrs/esm-patient-common-lib';
4
+ import {
5
+ DataTable,
6
+ DataTableSkeleton,
7
+ Table,
8
+ TableBody,
9
+ TableCell,
10
+ TableContainer,
11
+ TableHead,
12
+ TableHeader,
13
+ TableRow,
14
+ OverflowMenu,
15
+ OverflowMenuItem,
16
+ InlineLoading,
17
+ } from '@carbon/react';
18
+ import { ArrowDownLeft, ArrowLeft } from '@carbon/react/icons';
19
+ import styles from '../../manage-user.scss';
20
+ import { restBaseUrl, showModal, showSnackbar } from '@openmrs/esm-framework';
21
+ import { deleteUserRoleScopes, handleMutation, useUserRoleScopes } from '../../../../../user-management.resources';
22
+ import { User, UserRoleScope } from '../../../../../types';
23
+
24
+ interface StockUserRoleScopesListProps {
25
+ user?: User;
26
+ onEditUserRoleScope?: (userRoleScope: UserRoleScope) => void;
27
+ onAddUserRoleScope?: (isAddRoleScope: boolean) => void;
28
+ }
29
+
30
+ const StockUserRoleScopesList: React.FC<StockUserRoleScopesListProps> = ({ user, onEditUserRoleScope }) => {
31
+ const { t } = useTranslation();
32
+
33
+ // Fetch user role scopes
34
+ const { items: userRoleScopes, loadingRoleScope, isValidating } = useUserRoleScopes();
35
+ const [deletingUserScope, setDeletingUserScope] = useState(false);
36
+ const size = 'md';
37
+
38
+ const tableHeaders = useMemo(
39
+ () => [
40
+ { key: 'role', header: t('role', 'Role') },
41
+ { key: 'location', header: t('location', 'Location(s)') },
42
+ { key: 'stockOperation', header: t('stockOperation', 'Stock Operation') },
43
+ { key: 'permanent', header: t('permanent', 'Permanent') },
44
+ { key: 'enabled', header: t('enabled', 'Enabled') },
45
+ { key: 'actions', header: t('actions', 'Actions') },
46
+ ],
47
+ [t],
48
+ );
49
+
50
+ const showDeleteUserRoleScopeModal = useCallback(
51
+ (uuid: string) => {
52
+ const close = showModal('delete-stock-user-scope-modal', {
53
+ close: () => close(),
54
+ uuid,
55
+ onConfirmation: () => {
56
+ deleteUserRoleScopes([uuid])
57
+ .then(
58
+ () => {
59
+ handleMutation(`${restBaseUrl}/stockmanagement/userrolescope`);
60
+ setDeletingUserScope(false);
61
+ showSnackbar({
62
+ isLowContrast: true,
63
+ title: t('deletingstockUserScope', 'Delete Stock User Scope'),
64
+ kind: 'success',
65
+ subtitle: t('stockUserScopeDeletedSuccessfully', 'Stock User Scope Deleted Successfully'),
66
+ });
67
+ },
68
+ (error) => {
69
+ setDeletingUserScope(false);
70
+ showSnackbar({
71
+ title: t('errorDeletingUserScope', 'Error deleting a user scope'),
72
+ kind: 'error',
73
+ isLowContrast: true,
74
+ subtitle: error?.message,
75
+ });
76
+ },
77
+ )
78
+ .catch();
79
+ close();
80
+ },
81
+ });
82
+ },
83
+ [t],
84
+ );
85
+
86
+ const renderLocationIcon = (enableDescendants) => (enableDescendants ? <ArrowDownLeft /> : <ArrowLeft />);
87
+
88
+ const tableRows = useMemo(() => {
89
+ return (
90
+ (userRoleScopes?.results ?? [])
91
+ .filter((scope) => scope.userUuid === user.uuid)
92
+ .map((userRoleScope, index) => ({
93
+ id: index.toString(),
94
+ role: userRoleScope.role || 'N/A',
95
+ location: userRoleScope?.locations?.map((location) => (
96
+ <span key={`loc-${userRoleScope?.uuid}-${location.locationUuid}`}>
97
+ {location?.locationName} {renderLocationIcon(location?.enableDescendants)}
98
+ </span>
99
+ )),
100
+ stockOperation: userRoleScope?.operationTypes?.map((operation) => operation?.operationTypeName).join(', '),
101
+ permanent: userRoleScope.permanent ? t('yes', 'Yes') : t('no', 'No'),
102
+ enabled: userRoleScope.enabled ? t('yes', 'Yes') : t('no', 'No'),
103
+ actions: (
104
+ <OverflowMenu className={styles.btnSet}>
105
+ <OverflowMenuItem
106
+ onClick={() => {
107
+ onEditUserRoleScope(userRoleScope);
108
+ }}
109
+ itemText={t('edit', 'Edit')}
110
+ />
111
+ <OverflowMenuItem
112
+ hasDivider
113
+ isDelete
114
+ onClick={() => {
115
+ showDeleteUserRoleScopeModal(userRoleScope.uuid);
116
+ }}
117
+ itemText={t('delete', 'Delete')}
118
+ />
119
+ </OverflowMenu>
120
+ ),
121
+ })) || []
122
+ );
123
+ }, [userRoleScopes, t, user.uuid, showDeleteUserRoleScopeModal, onEditUserRoleScope]);
124
+
125
+ if (loadingRoleScope) {
126
+ return <DataTableSkeleton />;
127
+ }
128
+
129
+ return (
130
+ <div>
131
+ <CardHeader title="Manage User Role Scope">
132
+ {isValidating && <InlineLoading description={t('refreshingUserScopes', 'Refreshing user scopes...')} />}
133
+ </CardHeader>
134
+ <div className={styles.dataTable}>
135
+ <DataTable useZebraStyles size={size} rows={tableRows} headers={tableHeaders}>
136
+ {({ rows, headers, getHeaderProps, getRowProps, getTableProps }) => (
137
+ <TableContainer>
138
+ <Table {...getTableProps()} aria-label="user role scope table">
139
+ <TableHead>
140
+ <TableRow>
141
+ {headers.map((header) => (
142
+ <TableHeader {...getHeaderProps({ header })} key={header.key}>
143
+ {header.header}
144
+ </TableHeader>
145
+ ))}
146
+ </TableRow>
147
+ </TableHead>
148
+ <TableBody>
149
+ {rows.length > 0 ? (
150
+ rows.map((row) => (
151
+ <TableRow key={row.id} {...getRowProps({ row })}>
152
+ {row.cells.map((cell) => (
153
+ <TableCell key={cell.id}>{cell.value}</TableCell>
154
+ ))}
155
+ </TableRow>
156
+ ))
157
+ ) : (
158
+ <TableRow>
159
+ <TableCell colSpan={headers.length} className={styles.emptyTable}>
160
+ <EmptyState
161
+ displayText={t('noUserRoleScope', 'No user role scope')}
162
+ headerTitle={t('userRoleScope', 'User Role Scope')}
163
+ />
164
+ </TableCell>
165
+ </TableRow>
166
+ )}
167
+ </TableBody>
168
+ </Table>
169
+ </TableContainer>
170
+ )}
171
+ </DataTable>
172
+ </div>
173
+ </div>
174
+ );
175
+ };
176
+
177
+ export default StockUserRoleScopesList;
@@ -0,0 +1,117 @@
1
+ @use '@carbon/layout';
2
+ @use '@carbon/colors';
3
+
4
+ .roleStockFields {
5
+ display: flex;
6
+ flex-direction: column;
7
+ gap: layout.$spacing-05;
8
+ outline: 1px solid colors.$gray-10;
9
+ padding: layout.$spacing-05;
10
+ }
11
+
12
+ .checkBoxColumn {
13
+ background-color: colors.$gray-10;
14
+ margin: layout.$spacing-05;
15
+ padding: layout.$spacing-03;
16
+ border-radius: layout.$spacing-05;
17
+ }
18
+
19
+ .checkboxLabelSingleLine {
20
+ white-space: nowrap;
21
+ overflow: hidden;
22
+ text-overflow: ellipsis;
23
+ display: inline-block;
24
+ font-size: 14px;
25
+ }
26
+
27
+ .checkboxGroupGrid {
28
+ display: grid;
29
+ grid-template-columns: repeat(2, 1fr);
30
+ row-gap: layout.$spacing-03;
31
+ column-gap: layout.$spacing-02;
32
+ font-size: 14px;
33
+
34
+ :global(.cds--fieldset-legend) {
35
+ font-size: 14px;
36
+ }
37
+ }
38
+
39
+ .CheckboxGroup .bx--fieldset-legend {
40
+ font-size: 14px;
41
+ }
42
+
43
+ .btn {
44
+ min-width: 50%;
45
+ }
46
+
47
+ .checkboxLabelSelected {
48
+ background-color: colors.$green-10;
49
+ border-radius: layout.$spacing-05;
50
+ padding: layout.$spacing-02;
51
+ display: flex;
52
+ align-items: center;
53
+ font-size: 14px;
54
+ transition: background-color 0.3s ease;
55
+ }
56
+
57
+ .checkboxLabel {
58
+ background-color: transparent;
59
+ border-radius: layout.$spacing-05;
60
+ padding: layout.$spacing-02;
61
+ display: flex;
62
+ align-items: center;
63
+ transition: background-color 0.3s ease;
64
+ font-size: 14px;
65
+ }
66
+
67
+ .leftContainer {
68
+ display: flex;
69
+ flex-direction: column;
70
+ border-radius: layout.$spacing-05;
71
+ overflow: hidden;
72
+ }
73
+
74
+ .leftLayout {
75
+ display: flex;
76
+ flex-direction: row;
77
+ height: 100%;
78
+ }
79
+
80
+ .progressIndicator {
81
+ display: flex;
82
+ flex-direction: column;
83
+ min-width: 200px;
84
+ padding-top: layout.$spacing-03;
85
+ border-right: 1px solid colors.$gray-30;
86
+ }
87
+
88
+ .sections {
89
+ flex: 1;
90
+ padding: layout.$spacing-04;
91
+ }
92
+
93
+ @media (max-width: 768px) {
94
+ .leftLayout {
95
+ flex-direction: column;
96
+ }
97
+
98
+ .progressIndicator {
99
+ flex-direction: row;
100
+ border-right: none;
101
+ border-bottom: 1px solid colors.$gray-30;
102
+ min-width: unset;
103
+ justify-content: space-between;
104
+ padding: layout.$spacing-02;
105
+ }
106
+
107
+ .sections {
108
+ padding: layout.$spacing-03;
109
+ }
110
+ }
111
+
112
+ .multilineCheckboxLabel .cds--checkbox-label {
113
+ display: block;
114
+ white-space: normal;
115
+ word-wrap: break-word;
116
+ line-height: 1.4;
117
+ }
@@ -0,0 +1,290 @@
1
+ import React, { useEffect } from 'react';
2
+ import { Control, Controller, useFormContext } from 'react-hook-form';
3
+ import { useTranslation } from 'react-i18next';
4
+ import styles from './user-role-fields.scss';
5
+ import { formatDatetime, ResponsiveWrapper } from '@openmrs/esm-framework';
6
+ import {
7
+ DatePickerInput,
8
+ InlineLoading,
9
+ Button,
10
+ ComboBox,
11
+ CheckboxGroup,
12
+ Column,
13
+ Tile,
14
+ DatePicker,
15
+ } from '@carbon/react';
16
+ import { DATE_PICKER_CONTROL_FORMAT, DATE_PICKER_FORMAT, today } from '../../../../../constants';
17
+ import { Role, StockOperationType, UserRoleScope } from '../../../../../types';
18
+
19
+ type UserRoleScopeFields = {
20
+ field: Record<string, any>;
21
+ index: number;
22
+ control: Control<Record<string, any>>;
23
+ removeForm: (index: number) => void;
24
+ filteredInventoryRoles: Array<Role>;
25
+ hasInventoryRole: boolean;
26
+ stockOperations: Array<StockOperationType>;
27
+ loadingStock: boolean;
28
+ stockLocations: Array<fhir.Location>;
29
+ roleScopeformMethods: any;
30
+ userRoleScopeInitialValues: UserRoleScope;
31
+ };
32
+ const MinDate: Date = today();
33
+
34
+ const UserRoleScopeFormFields: React.FC<UserRoleScopeFields> = ({
35
+ field,
36
+ index,
37
+ control,
38
+ removeForm,
39
+ filteredInventoryRoles,
40
+ hasInventoryRole,
41
+ stockOperations,
42
+ loadingStock,
43
+ stockLocations,
44
+ roleScopeformMethods,
45
+ userRoleScopeInitialValues,
46
+ }) => {
47
+ const { t } = useTranslation();
48
+ const { watch, setValue } = useFormContext();
49
+ const enabled = watch(`forms.${index}.enabled`);
50
+ const permanent = watch(`forms.${index}.permanent`);
51
+
52
+ const handlePermissionDurationChange = (e, field, setValue) => {
53
+ const isChecked = e.target.checked;
54
+ field.onChange(isChecked);
55
+
56
+ if (isChecked) {
57
+ setValue(`forms.${index}.dateRange`, { activeFrom: undefined, activeTo: undefined });
58
+ }
59
+ };
60
+
61
+ useEffect(() => {
62
+ if (permanent) {
63
+ setValue(`forms.${index}.dateRange`, { activeFrom: undefined, activeTo: undefined });
64
+ }
65
+ }, [permanent, setValue, index]);
66
+
67
+ return (
68
+ <div className={styles.roleStockFields}>
69
+ <ResponsiveWrapper>
70
+ <Controller
71
+ name={`forms.${index}.role`}
72
+ control={control}
73
+ render={({ field }) => (
74
+ <ComboBox
75
+ {...field}
76
+ id="role"
77
+ items={filteredInventoryRoles}
78
+ itemToString={(item) => item?.display?.trim() || ''}
79
+ placeholder={t('chooseAStockRole', 'Choose a stock role')}
80
+ titleText={t('stockRole', 'Stock Role')}
81
+ selectedItem={filteredInventoryRoles.find((item) => item?.display === field.value) || null}
82
+ onChange={({ selectedItem }) => {
83
+ field.onChange(selectedItem ? selectedItem.display.trim() : '');
84
+ }}
85
+ disabled={!!userRoleScopeInitialValues}
86
+ />
87
+ )}
88
+ />
89
+ </ResponsiveWrapper>
90
+ <ResponsiveWrapper>
91
+ <Column xsm={8} md={12} lg={12} className={styles.checkBoxColumn}>
92
+ <CheckboxGroup legendText={t('stockRoleAccess', 'Stock Role Access')} className={styles.checkboxGroupGrid}>
93
+ <Controller
94
+ name={`forms.${index}.enabled`}
95
+ control={control}
96
+ render={({ field }) => (
97
+ <div>
98
+ <label htmlFor="enable">
99
+ <input
100
+ type="checkbox"
101
+ id="enable"
102
+ name="enabled"
103
+ checked={field.value || false}
104
+ onChange={(e) => field.onChange(e.target.checked)}
105
+ />
106
+ {t('enable', 'Enable?')}
107
+ </label>
108
+ </div>
109
+ )}
110
+ />
111
+ {enabled && (
112
+ <Controller
113
+ name={`forms.${index}.permanent`}
114
+ control={control}
115
+ render={({ field }) => (
116
+ <div>
117
+ <label htmlFor="permanent">
118
+ <input
119
+ type="checkbox"
120
+ id="permanent"
121
+ name="permanent"
122
+ checked={field.value || false}
123
+ onChange={(e) => handlePermissionDurationChange(e, field, roleScopeformMethods.setValue)}
124
+ />
125
+ {t('permanent', 'Permanent?')}
126
+ </label>
127
+ </div>
128
+ )}
129
+ />
130
+ )}
131
+ </CheckboxGroup>
132
+ {!permanent && enabled && (
133
+ <ResponsiveWrapper>
134
+ <Tile>
135
+ <Controller
136
+ name={`forms.${index}.dateRange`}
137
+ control={control}
138
+ render={({ field }) => {
139
+ const { value, onChange } = field;
140
+
141
+ const handleDateChange = (dates: Array<Date>) => {
142
+ onChange({
143
+ activeFrom: dates[0],
144
+ activeTo: dates[1],
145
+ });
146
+ };
147
+
148
+ return (
149
+ <DatePicker
150
+ datePickerType="range"
151
+ light
152
+ minDate={formatDatetime(MinDate)}
153
+ locale="en"
154
+ dateFormat={DATE_PICKER_CONTROL_FORMAT}
155
+ onChange={handleDateChange}
156
+ value={[value?.activeFrom, value?.activeTo]}>
157
+ <DatePickerInput
158
+ id="date-picker-input-id-start"
159
+ placeholder={DATE_PICKER_FORMAT}
160
+ labelText={t('activeFrom', 'Active From')}
161
+ />
162
+ <DatePickerInput
163
+ id="date-picker-input-id-finish"
164
+ placeholder={DATE_PICKER_FORMAT}
165
+ labelText={t('activeTo', 'Active To')}
166
+ />
167
+ </DatePicker>
168
+ );
169
+ }}
170
+ />
171
+ </Tile>
172
+ </ResponsiveWrapper>
173
+ )}
174
+ </Column>
175
+ </ResponsiveWrapper>
176
+ <ResponsiveWrapper>
177
+ <Column xsm={8} md={12} lg={12} className={styles.checkBoxColumn}>
178
+ <CheckboxGroup legendText={t('stockOperation', 'Stock Operation')} className={styles.checkboxGroupGrid}>
179
+ {loadingStock ? (
180
+ <InlineLoading status="active" iconDescription="Loading" description="Loading data..." />
181
+ ) : (
182
+ <Controller
183
+ name={`forms.${index}.operationTypes`}
184
+ control={control}
185
+ render={({ field }) => {
186
+ const selectedStockOperation = field.value || [];
187
+
188
+ const isSelected = (operationUuid: string) =>
189
+ selectedStockOperation.some((op) => op.operationTypeUuid === operationUuid);
190
+ const toggleOperation = (operation) => {
191
+ if (isSelected(operation.uuid)) {
192
+ field.onChange(selectedStockOperation.filter((op) => op.operationTypeUuid !== operation.uuid));
193
+ } else {
194
+ field.onChange([
195
+ ...selectedStockOperation,
196
+ {
197
+ operationTypeUuid: operation.uuid,
198
+ operationTypeName: operation.name,
199
+ },
200
+ ]);
201
+ }
202
+ };
203
+
204
+ return (
205
+ <>
206
+ {stockOperations?.length > 0 &&
207
+ stockOperations.map((operation) => {
208
+ return (
209
+ <label
210
+ key={operation.uuid}
211
+ className={
212
+ isSelected(operation.uuid) ? styles.checkboxLabelSelected : styles.checkboxLabel
213
+ }>
214
+ <input
215
+ type="checkbox"
216
+ id={operation.uuid}
217
+ checked={isSelected(operation.uuid)}
218
+ onChange={() => toggleOperation(operation)}
219
+ />
220
+ {operation.name}
221
+ </label>
222
+ );
223
+ })}
224
+ </>
225
+ );
226
+ }}
227
+ />
228
+ )}
229
+ </CheckboxGroup>
230
+ </Column>
231
+ </ResponsiveWrapper>
232
+ <ResponsiveWrapper>
233
+ <Column xsm={8} md={12} lg={12} className={styles.checkBoxColumn}>
234
+ <CheckboxGroup legendText={t('stockLocation', 'Stock Location')} className={styles.checkboxGroupGrid}>
235
+ {loadingStock ? (
236
+ <InlineLoading status="active" iconDescription="Loading" description="Loading data..." />
237
+ ) : (
238
+ <Controller
239
+ name={`forms.${index}.locations`}
240
+ control={control}
241
+ render={({ field }) => {
242
+ const selectedLocations = field.value || [];
243
+
244
+ const isSelected = (locationUuid: string) =>
245
+ selectedLocations.some((loc) => loc.locationUuid === locationUuid);
246
+ const toggleLocation = (location) => {
247
+ if (isSelected(location.id)) {
248
+ field.onChange(selectedLocations.filter((loc) => loc.locationUuid !== location.id));
249
+ } else {
250
+ field.onChange([
251
+ ...selectedLocations,
252
+ { locationName: location.name, locationUuid: location.id },
253
+ ]);
254
+ }
255
+ };
256
+
257
+ return (
258
+ <>
259
+ {stockLocations?.length > 0 &&
260
+ stockLocations.map((location) => (
261
+ <label
262
+ key={location.id}
263
+ className={isSelected(location.id) ? styles.checkboxLabelSelected : styles.checkboxLabel}>
264
+ <input
265
+ type="checkbox"
266
+ id={location.id}
267
+ checked={isSelected(location.id)}
268
+ onChange={() => toggleLocation(location)}
269
+ />
270
+ {location.name}
271
+ </label>
272
+ ))}
273
+ </>
274
+ );
275
+ }}
276
+ />
277
+ )}
278
+ </CheckboxGroup>
279
+ </Column>
280
+ </ResponsiveWrapper>
281
+ {!userRoleScopeInitialValues && (
282
+ <Button size="sm" kind="danger--tertiary" onClick={() => removeForm(index)}>
283
+ {t('remove', 'Remove')}
284
+ </Button>
285
+ )}
286
+ </div>
287
+ );
288
+ };
289
+
290
+ export default UserRoleScopeFormFields;