Skip to content

Commit

Permalink
OH2-404 | Implement supplier deletion (#677)
Browse files Browse the repository at this point in the history
* chore:update suppliers api

* feat:OH2-404 | supplier deletion
  • Loading branch information
SilverD3 authored Oct 22, 2024
1 parent 3f5206d commit d5daf9e
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 22 deletions.
8 changes: 8 additions & 0 deletions src/components/accessories/admin/suppliers/Suppliers.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import React from "react";

import { useAppDispatch } from "libraries/hooks/redux";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router";
import { deleteSupplier } from "state/suppliers";
import { PATHS } from "../../../../consts";
import { SupplierDTO } from "../../../../generated";
import Button from "../../button/Button";
import SuppliersTable from "./suppliersTable";

export const Suppliers = () => {
const navigate = useNavigate();
const dispatch = useAppDispatch();
const { t } = useTranslation();

const handleEdit = (row: SupplierDTO) => {
Expand All @@ -17,9 +20,14 @@ export const Suppliers = () => {
});
};

const handleDelete = (row: SupplierDTO) => {
dispatch(deleteSupplier(row.supId));
};

return (
<SuppliersTable
onEdit={handleEdit}
onDelete={handleDelete}
headerActions={
<Button
onClick={() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,34 @@
import { CircularProgress } from "@mui/material";
import ConfirmationDialog from "components/accessories/confirmationDialog/ConfirmationDialog";
import { useAppDispatch, useAppSelector } from "libraries/hooks/redux";
import React, { ReactNode, useEffect } from "react";
import React, { ReactNode, useEffect, useRef } from "react";
import { useTranslation } from "react-i18next";
import { SupplierDTO } from "../../../../../generated";
import { getSuppliers } from "../../../../../state/suppliers";
import {
deleteSupplierReset,
getSuppliers,
} from "../../../../../state/suppliers";
import InfoBox from "../../../infoBox/InfoBox";
import Table from "../../../table/Table";
import { TFilterField } from "../../../table/filter/types";
import classes from "./SuppliersTable.module.scss";

import checkIcon from "../../../../../assets/check-icon.png";

interface IOwnProps {
onEdit: (row: any) => void;
onDelete: (row: any) => void;
headerActions?: ReactNode;
}

export const SuppliersTable = ({ onEdit, headerActions }: IOwnProps) => {
export const SuppliersTable = ({
onEdit,
onDelete,
headerActions,
}: IOwnProps) => {
const dispatch = useAppDispatch();
const { t } = useTranslation();
const infoBoxRef = useRef<HTMLDivElement>(null);

useEffect(() => {
dispatch(getSuppliers());
Expand Down Expand Up @@ -44,6 +56,8 @@ export const SuppliersTable = ({ onEdit, headerActions }: IOwnProps) => {
(state) => state.suppliers.supplierList
);

const deleteSupplier = useAppSelector((state) => state.suppliers.delete);

const formatDataToDisplay = (data: SupplierDTO[]) => {
return data.map((item) => {
return {
Expand Down Expand Up @@ -78,20 +92,48 @@ export const SuppliersTable = ({ onEdit, headerActions }: IOwnProps) => {

case "SUCCESS":
return (
<Table
rowData={formatDataToDisplay(data ?? [])}
tableHeader={header}
labelData={label}
columnsOrder={order}
rowsPerPage={10}
isCollapsabile={true}
onEdit={handleEdit}
filterColumns={filters}
showEmptyCell={false}
rowKey="name"
manualFilter={false}
headerActions={headerActions}
/>
<>
<Table
rowData={formatDataToDisplay(data ?? [])}
tableHeader={header}
labelData={label}
columnsOrder={order}
rowsPerPage={10}
isCollapsabile={true}
onEdit={handleEdit}
onDelete={onDelete}
filterColumns={filters}
showEmptyCell={false}
rowKey="name"
manualFilter={false}
headerActions={headerActions}
/>
{deleteSupplier.isLoading && (
<div ref={infoBoxRef} className="info-box-container">
<InfoBox type="info" message={t("supplier.deleting")} />
</div>
)}
{deleteSupplier.status === "FAIL" && (
<div ref={infoBoxRef} className="info-box-container">
<InfoBox
type="error"
message={deleteSupplier.error?.message || "unknown error"}
/>
</div>
)}
<ConfirmationDialog
isOpen={deleteSupplier.status === "SUCCESS"}
title={t("supplier.deleted")}
icon={checkIcon}
info={t("supplier.deleteSuccess")}
primaryButtonLabel="Ok"
handlePrimaryButtonClick={() => {
dispatch(getSuppliers());
dispatch(deleteSupplierReset());
}}
handleSecondaryButtonClick={() => ({})}
/>
</>
);
case "SUCCESS_EMPTY":
return <InfoBox type="info" message={t("common.emptydata")} />;
Expand Down
22 changes: 22 additions & 0 deletions src/generated/apis/SuppliersApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ import {
SupplierDTO,
} from '../models';

export interface DeleteSupplierRequest {
id: number;
}

export interface GetSuppliersRequest {
excludeDeleted?: boolean;
}
Expand All @@ -38,6 +42,24 @@ export interface UpdateSupplierRequest {
*/
export class SuppliersApi extends BaseAPI {

/**
*/
deleteSupplier({ id }: DeleteSupplierRequest): Observable<void>
deleteSupplier({ id }: DeleteSupplierRequest, opts?: OperationOpts): Observable<void | RawAjaxResponse<void>>
deleteSupplier({ id }: DeleteSupplierRequest, opts?: OperationOpts): Observable<void | RawAjaxResponse<void>> {
throwIfNullOrUndefined(id, 'id', 'deleteSupplier');

const headers: HttpHeaders = {
...(this.configuration.username != null && this.configuration.password != null ? { Authorization: `Basic ${btoa(this.configuration.username + ':' + this.configuration.password)}` } : undefined),
};

return this.request<void>({
url: '/suppliers/{id}'.replace('{id}', encodeURI(id)),
method: 'DELETE',
headers,
}, opts?.responseOpts);
};

/**
*/
getSuppliers({ excludeDeleted }: GetSuppliersRequest): Observable<Array<SupplierDTO>>
Expand Down
25 changes: 25 additions & 0 deletions src/generated/models/GroupPermissionsDTO.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// tslint:disable
/**
* Open Hospital API Documentation
* Open Hospital API Documentation
*
* The version of the OpenAPI document: 0.1.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/

/**
* @export
* @interface GroupPermissionsDTO
*/
export interface GroupPermissionsDTO {
/**
* List of permissions\' ids
* @type {Array<number>}
* @memberof GroupPermissionsDTO
*/
permissions?: Array<number>;
}
5 changes: 4 additions & 1 deletion src/resources/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1040,7 +1040,10 @@
"updated": "Supplier updated",
"updateSuccess": "Supplier has been updated successfully!",
"created": "Supplier created",
"createSuccess": "Supplier has been created successfully!"
"createSuccess": "Supplier has been created successfully!",
"deleted": "Supplier deleted",
"deleting": "Deleting supplier...",
"deleteSuccess": "Supplier has been deleted successfully!"
},
"ward": {
"code": "Code",
Expand Down
17 changes: 14 additions & 3 deletions src/state/suppliers/slice.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { createSlice } from "@reduxjs/toolkit";
import { isEmpty } from "lodash";
import { ApiResponse } from "state/types";
import { initial } from "./initial";
import * as thunks from "./thunk";
import { ApiResponse } from "state/types";
import { isEmpty } from "lodash";

export const supplierSlice = createSlice({
name: "suppliers",
Expand All @@ -26,7 +26,8 @@ export const supplierSlice = createSlice({
})
.addCase(thunks.getSuppliers.fulfilled, (state, action) => {
state.supplierList = isEmpty(action.payload)
? ApiResponse.empty() : ApiResponse.value(action.payload);
? ApiResponse.empty()
: ApiResponse.value(action.payload);
})
.addCase(thunks.getSuppliers.rejected, (state, action) => {
state.supplierList = ApiResponse.error(action.payload);
Expand All @@ -50,6 +51,16 @@ export const supplierSlice = createSlice({
})
.addCase(thunks.updateSupplier.rejected, (state, action) => {
state.update = ApiResponse.error(action.payload);
})
// Delete Supplier
.addCase(thunks.deleteSupplier.pending, (state) => {
state.delete = ApiResponse.loading();
})
.addCase(thunks.deleteSupplier.fulfilled, (state, action) => {
state.delete = ApiResponse.value(action.payload);
})
.addCase(thunks.deleteSupplier.rejected, (state, action) => {
state.delete = ApiResponse.error(action.payload);
}),
});

Expand Down
9 changes: 9 additions & 0 deletions src/state/suppliers/thunk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,12 @@ export const updateSupplier = createAsyncThunk(
.toPromise()
.catch((error) => thunkApi.rejectWithValue(error.response))
);

export const deleteSupplier = createAsyncThunk(
"suppliers/deleteSupplier",
async (id: number, thunkApi) =>
api
.deleteSupplier({ id })
.toPromise()
.catch((error) => thunkApi.rejectWithValue(error.response))
);
2 changes: 1 addition & 1 deletion src/state/suppliers/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ export type ISupplierState = {
supplierList: ApiResponse<Array<SupplierDTO>>;
create: ApiResponse<SupplierDTO>;
update: ApiResponse<SupplierDTO>;
delete: ApiResponse<boolean>;
delete: ApiResponse<void>;
};

0 comments on commit d5daf9e

Please sign in to comment.