Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TM-1385] Admin create user funtionality #706

Merged
merged 2 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/admin/apiProvider/dataProviders/userDataProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ import {
fetchGetV2AdminUsersExport,
fetchGetV2AdminUsersMulti,
fetchGetV2AdminUsersUUID,
fetchPostV2AdminUsersCreate,
fetchPutV2AdminUsersUUID,
GetV2AdminUsersError,
GetV2AdminUsersExportError,
GetV2AdminUsersMultiError,
GetV2AdminUsersUUIDError,
PostV2AdminUsersCreateError,
PutV2AdminUsersUUIDError
} from "@/generated/apiComponents";
import { V2AdminUserRead } from "@/generated/apiSchemas";
Expand All @@ -34,6 +36,19 @@ const normalizeUserObject = (item: V2AdminUserRead) => ({
});

export const userDataProvider: UserDataProvider = {
//@ts-ignore
async create(__, params) {
try {
const response = await fetchPostV2AdminUsersCreate({
body: params.data
});

// @ts-expect-error
return { data: { ...response.data, id: response.id } };
} catch (err) {
throw getFormattedErrorForRA(err as PostV2AdminUsersCreateError);
}
},
//@ts-ignore
async getList(_, params) {
try {
Expand Down
1 change: 1 addition & 0 deletions src/admin/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const App = () => {
list={modules.user.List}
show={modules.user.Show}
edit={modules.user.Edit}
create={modules.user.Create}
icon={() => <Icon className="h-8 w-8" name={IconNames.USERS} />}
/>
<Resource
Expand Down
4 changes: 3 additions & 1 deletion src/admin/modules/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import SiteReportShow from "./siteReports/components/SiteReportShow";
import { SiteReportsList } from "./siteReports/components/SiteReportsList";
import SiteShow from "./sites/components/SiteShow";
import { SitesList } from "./sites/components/SitesList";
import UserCreate from "./user/components/UserCreate";
import UserEdit from "./user/components/UserEdit";
import { UserList } from "./user/components/UserList";
import { UserShow } from "./user/components/UserShow";
Expand All @@ -45,7 +46,8 @@ const user = {
ResourceName: "user",
List: UserList,
Show: UserShow,
Edit: UserEdit
Edit: UserEdit,
Create: UserCreate
};

const organisation = {
Expand Down
76 changes: 76 additions & 0 deletions src/admin/modules/user/components/UserCreate.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import {
AutocompleteInput,
Create,
ReferenceInput,
SelectArrayInput,
SelectInput,
SimpleForm,
TextInput
} from "react-admin";
import * as yup from "yup";

import { useGetUserRole } from "@/admin/hooks/useGetUserRole";
import {
countriesChoices,
directFrameworkChoices,
frameworkChoices,
userPrimaryRoleChoices
} from "@/admin/modules/user/const";
import { validateForm } from "@/admin/utils/forms";

import modules from "../..";

const UserCreate = () => {
const { isSuperAdmin } = useGetUserRole();

const schemaObject: any = {
first_name: yup.string().nullable().required("First Name is required"),
last_name: yup.string().nullable().required("Last Name is required"),
email_address: yup.string().nullable().required("Email Address is required").email("Invalid email format"),
phone_number: yup.string().nullable(),
job_role: yup.string().nullable(),
organisation: yup.object().nullable(),
program: yup.string().nullable(),
country: yup.string().nullable()
};

if (isSuperAdmin) {
schemaObject.role = yup.string().required("Role is required");
}

return (
<Create title="Create User">
<SimpleForm validate={validateForm(yup.object(schemaObject))}>
<TextInput source="first_name" label="First Name" fullWidth />
<TextInput source="last_name" label="Last Name" fullWidth />
<TextInput source="email_address" label="Professional Email Address" fullWidth type="email" />
<TextInput source="phone_number" label="Professional Phone Number" fullWidth type="tel" />
<TextInput source="job_role" label="Job Title" fullWidth />

<ReferenceInput
label="Organisation"
source="organisation.uuid"
reference={modules.organisation.ResourceName}
options={{ fullWidth: true }}
>
<AutocompleteInput label="Organisation" optionText="name" fullWidth />
</ReferenceInput>

{isSuperAdmin && <SelectInput source="role" label="Role" choices={userPrimaryRoleChoices} fullWidth />}

<SelectInput source="program" label="Program" choices={frameworkChoices} fullWidth />

<SelectInput source="country" label="Country" choices={countriesChoices} fullWidth />

<SelectArrayInput
source="direct_frameworks"
label="Direct Frameworks"
choices={directFrameworkChoices}
fullWidth
/>
</SimpleForm>
</Create>
);
};

export default UserCreate;
51 changes: 49 additions & 2 deletions src/admin/modules/user/components/UserShowAside.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,36 @@
import { Box, Button, Divider, Grid, Stack, Typography } from "@mui/material";
import { useState } from "react";
import { BooleanField, RaRecord, SelectField, TextField, useNotify, useRefresh, useShowContext } from "react-admin";
import {
BooleanField,
RaRecord,
SelectField,
TextField,
useNotify,
useRedirect,
useRefresh,
useShowContext
} from "react-admin";
import { When } from "react-if";

import Aside from "@/admin/components/Aside/Aside";
import { ConfirmationDialog } from "@/admin/components/Dialogs/ConfirmationDialog";
import { useGetUserRole } from "@/admin/hooks/useGetUserRole";
import { ResetPasswordDialog } from "@/admin/modules/user/components/ResetPasswordDialog";
import { usePatchV2AdminUsersVerifyUUID, usePostAuthReset, usePostV2UsersResend } from "@/generated/apiComponents";
import {
usePatchV2AdminUsersVerifyUUID,
usePostAuthReset,
usePostAuthSendLoginDetails,
usePostV2UsersResend
} from "@/generated/apiComponents";
import { V2AdminUserRead } from "@/generated/apiSchemas";

import { userPrimaryRoleChoices } from "../const";

export const UserShowAside = () => {
const notify = useNotify();
const refresh = useRefresh();
const redirect = useRedirect();
const { isSuperAdmin } = useGetUserRole();

const [showResetPasswordDialog, setShowResetPasswordDialog] = useState(false);
const [showVerifyEmailDialog, setShowVerifyEmailDialog] = useState(false);
Expand All @@ -34,13 +52,24 @@ export const UserShowAside = () => {
}
});

const { mutate: sendLoginDetails } = usePostAuthSendLoginDetails({
onSuccess() {
notify(`Login details email has been sent successfully.`, { type: "success" });
refresh();
}
});

const { mutate: verifyUser } = usePatchV2AdminUsersVerifyUUID({
onSuccess() {
notify(`User email has been verified successfully.`, { type: "success" });
refresh();
}
});

const handleCreateUser = () => {
redirect("create", "user");
};

return (
<>
<Aside title="User Review">
Expand All @@ -65,6 +94,24 @@ export const UserShowAside = () => {
<Divider />
<Box pt={2}>
<Stack direction="row" alignItems="center" gap={2} flexWrap="wrap">
<When condition={isSuperAdmin}>
<Button variant="contained" onClick={handleCreateUser}>
Create User
</Button>
</When>
<Button
variant="contained"
onClick={() =>
sendLoginDetails({
body: {
email_address: record?.email_address,
callback_url: window.location.origin + "/auth/set-password/"
}
})
}
>
Send Login Details
</Button>
<Button
variant="contained"
onClick={() =>
Expand Down
Loading