From 3e534ff9613b2f34e34c0e866d9fc88731da1b23 Mon Sep 17 00:00:00 2001 From: pranalidhanavade Date: Tue, 10 Oct 2023 20:56:00 +0530 Subject: [PATCH] feat:added edit ecosystem modal component Signed-off-by: pranalidhanavade --- src/api/ecosystem.ts | 11 +- src/components/Ecosystem/Dashboard.tsx | 103 ++++-- src/components/Ecosystem/interfaces/index.ts | 1 + .../EditEcosystemOrgModal/index.tsx | 340 ++++++++++++++++++ .../organization/interfaces/index.ts | 2 + .../invitations/SendInvitationModal.tsx | 4 +- 6 files changed, 427 insertions(+), 34 deletions(-) create mode 100644 src/components/EditEcosystemOrgModal/index.tsx diff --git a/src/api/ecosystem.ts b/src/api/ecosystem.ts index 863b44783..39d2584c4 100644 --- a/src/api/ecosystem.ts +++ b/src/api/ecosystem.ts @@ -8,7 +8,7 @@ interface DataPayload { name: string description: string logo: string - tags: string + tags?: string userId: number } @@ -41,10 +41,12 @@ export const createEcosystems = async (dataPayload: DataPayload) => { } } -export const updateEcosystem = async (data: object) => { +export const updateEcosystem = async (dataPayload: DataPayload) => { const orgId = await getFromLocalStorage(storageKeys.ORG_ID); - const url = `${apiRoutes.Ecosystem.root}/${orgId}` - const payload = data + const ecosystemId = await getFromLocalStorage(storageKeys.ECOSYSTEM_ID); + + const url = `${apiRoutes.Ecosystem.root}/${ecosystemId}/${orgId}` + const payload = dataPayload const token = await getFromLocalStorage(storageKeys.TOKEN) const config = { headers: { @@ -67,6 +69,7 @@ export const updateEcosystem = async (data: object) => { } } + export const getEcosystem = async () => { const orgId = await getFromLocalStorage(storageKeys.ORG_ID); const url = `${apiRoutes.Ecosystem.root}/${orgId}` diff --git a/src/components/Ecosystem/Dashboard.tsx b/src/components/Ecosystem/Dashboard.tsx index 77510ec88..6ee02085d 100644 --- a/src/components/Ecosystem/Dashboard.tsx +++ b/src/components/Ecosystem/Dashboard.tsx @@ -17,6 +17,8 @@ import checkEcosystem from '../../config/ecosystem'; import RoleViewButton from '../RoleViewButton'; import SendInvitationModal from '../organization/invitations/SendInvitationModal'; import { setToLocalStorage } from '../../api/Auth'; +import { Dropdown } from 'flowbite-react'; +import EditPopupModal from '../EditEcosystemOrgModal'; const Dashboard = () => { const [ecosystemDetails, setEcosystemDetails] = useState(); @@ -25,39 +27,48 @@ const Dashboard = () => { const [failure, setFailure] = useState(null); const [message, setMessage] = useState(null); const [loading, setLoading] = useState(true); - const[ecosystemId,setEcosystemId]=useState('') + const [ecosystemId, setEcosystemId] = useState('') const [openModal, setOpenModal] = useState(false); - const props = { openModal, setOpenModal }; + const [editOpenModal, setEditOpenModal] = useState(false); + const [dropdownOpen, setDropdownOpen] = useState(false); const createEcosystemModel = () => { - props.setOpenModal(true); + setOpenModal(true); }; const createInvitationsModel = () => { - props.setOpenModal(true); + setOpenModal(true); }; - + const EditEcosystemOrgModal = () => { + setEditOpenModal(true); + }; + + const handleEditModalClose = () => { + setEditOpenModal(false); + setDropdownOpen(false); // Close the dropdown when the edit modal is closed + }; + const fetchEcosystemDetails = async () => { - + setLoading(true); const response = await getEcosystem(); const { data } = response as AxiosResponse; - if (data?.statusCode === apiStatusCodes.API_STATUS_SUCCESS) { - const ecosystemData = data?.data[0] - await setToLocalStorage(storageKeys.ECOSYSTEM_ID,ecosystemData?.id) - setEcosystemId(ecosystemData?.id) - setEcosystemDetails({ - logoUrl: ecosystemData.logoUrl, - name: ecosystemData.name, - description: ecosystemData.description - }) - } else { - setFailure(response as string) - } - setLoading(false) - } + if (data?.statusCode === apiStatusCodes.API_STATUS_SUCCESS) { + const ecosystemData = data?.data[0] + await setToLocalStorage(storageKeys.ECOSYSTEM_ID, ecosystemData?.id) + setEcosystemId(ecosystemData?.id) + setEcosystemDetails({ + logoUrl: ecosystemData.logoUrl, + name: ecosystemData.name, + description: ecosystemData.description + }) + } else { + setFailure(response as string) + } + setLoading(false) + } useEffect(() => { fetchEcosystemDetails(); @@ -111,9 +122,9 @@ const Dashboard = () => { setMessage(data)} - setOpenModal={props.setOpenModal} + setOpenModal={setOpenModal} /> { } onClickEvent={createInvitationsModel} /> -
- setDropdownOpen(!dropdownOpen)} + renderTrigger={() => -
+ } + > + +
+ Edit Ecosystem +
+
+ +
+ Enable/Disable Ecosystem +
+
+ +
+ Manual Registration +
+
+ + + )} @@ -186,6 +219,18 @@ const Dashboard = () => {
+ { + setSuccess(value); + // setDropdownOpen(false); + + }} + isOrganization={false} + onEditSuccess={handleEditModalClose} + entityData={ecosystemDetails} + /> )} @@ -200,13 +245,14 @@ const Dashboard = () => {
{ setSuccess(value); fetchEcosystemDetails(); }} isorgModal={false} /> + { )}
)} + ); }; diff --git a/src/components/Ecosystem/interfaces/index.ts b/src/components/Ecosystem/interfaces/index.ts index 3772fadde..14f9608b0 100644 --- a/src/components/Ecosystem/interfaces/index.ts +++ b/src/components/Ecosystem/interfaces/index.ts @@ -15,4 +15,5 @@ export interface Ecosystem { logoUrl: string website: string roles: string[] + logoFile:string } \ No newline at end of file diff --git a/src/components/EditEcosystemOrgModal/index.tsx b/src/components/EditEcosystemOrgModal/index.tsx new file mode 100644 index 000000000..adf9401df --- /dev/null +++ b/src/components/EditEcosystemOrgModal/index.tsx @@ -0,0 +1,340 @@ +import * as yup from "yup"; +import { Avatar, Button, Label, Modal } from 'flowbite-react'; +import { Field, Form, Formik, FormikHelpers } from 'formik'; +import { IMG_MAX_HEIGHT, IMG_MAX_WIDTH, apiStatusCodes, imageSizeAccepted } from '../../config/CommonConstant'; +import { calculateSize, dataURItoBlob } from "../../utils/CompressImage"; +import { AlertComponent } from "../AlertComponent"; +import type { AxiosResponse } from 'axios'; +import { updateOrganization } from "../../api/organization"; +import { updateEcosystem } from "../../api/ecosystem"; +import type { Organisation } from "../organization/interfaces"; +import type { Ecosystem } from "../Ecosystem/interfaces"; +import React, { useEffect, useState } from "react"; + +interface EditEntityModalProps { + openModal: boolean; + setMessage: (message: string) => void; + setOpenModal: (flag: boolean) => void; + onEditSuccess?: () => void; + entityData: Organisation | Ecosystem | null; + isOrganization: boolean; // Indicates whether it's an organization or ecosystem +} + +interface EditEntityValues { + name: string; + description: string; +} + +interface ILogoImage { + logoFile: string | File; + imagePreviewUrl: string | ArrayBuffer | null | File; + fileName: string; +} + +const EditPopupModal = (props: EditEntityModalProps) => { + const [logoImage, setLogoImage] = useState({ + logoFile: "", + imagePreviewUrl: props?.entityData?.logoUrl ?? "", + fileName: '', + }); + + const [loading, setLoading] = useState(false); + const [isImageEmpty, setIsImageEmpty] = useState(false); + const [initialEntityData, setInitialEntityData] = useState({ + name: "", + description: "", + }); + + useEffect(() => { + console.log(6565, props.entityData) + if (props.openModal && props.entityData) { + setInitialEntityData({ + name: props.entityData.name ?? "", + description: props.entityData.description ?? "", + }); + setLogoImage({ + logoFile: "", + imagePreviewUrl: props.entityData.logoUrl ?? "", + fileName: props.entityData.logoFile ?? "", + }); + } + }, [props.entityData, props.openModal]); + + const [errMsg, setErrMsg] = useState(null); + const [imgError, setImgError] = useState(''); + + useEffect(() => { + if (!props.openModal) { + setInitialEntityData({ + name: "", + description: "", + }); + + setLogoImage({ + logoFile: "", + imagePreviewUrl: "", + fileName: "", + }); + setImgError(''); + setErrMsg(null); + setLoading(false); + } + }, [props.openModal]); + // Function to process image + const processImage = (e: any): string | undefined => { + const file = e?.target?.files[0]; + if (!file) return; + + const reader = new FileReader(); + reader.readAsDataURL(file); + + reader.onload = (event): void => { + const imgElement = document.createElement("img"); + if (imgElement) { + imgElement.src = typeof event?.target?.result === 'string' ? event.target.result : ""; + imgElement.onload = (e): void => { + let fileUpdated: File | string = file; + let srcEncoded = ''; + const canvas = document.createElement("canvas"); + + const { width, height, ev } = calculateSize(imgElement, IMG_MAX_WIDTH, IMG_MAX_HEIGHT); + canvas.width = width; + canvas.height = height; + + const ctx = canvas.getContext("2d"); + if (ctx && e?.target) { + ctx.imageSmoothingEnabled = true; + ctx.imageSmoothingQuality = "high"; + ctx.drawImage(ev, 0, 0, canvas.width, canvas.height); + srcEncoded = ctx.canvas.toDataURL(ev, file.type); + const blob = dataURItoBlob(srcEncoded, file.type); + fileUpdated = new File([blob], file.name, { type: file.type, lastModified: new Date().getTime() }); + setLogoImage({ + logoFile: fileUpdated, + imagePreviewUrl: srcEncoded, + fileName: file.name + }); + } + }; + } + }; + }; + + // Function to handle image change + const handleImageChange = (event: any): void => { + setImgError(''); + const reader = new FileReader(); + const file = event?.target?.files; + + const fileSize = Number((file[0]?.size / 1024 / 1024)?.toFixed(2)); + const extension = file[0]?.name?.substring(file[0]?.name?.lastIndexOf(".") + 1)?.toLowerCase(); + + if (extension === "png" || extension === "jpeg" || extension === "jpg") { + if (fileSize <= imageSizeAccepted) { + reader.onloadend = (): void => { + processImage(event); + setIsImageEmpty(false); + }; + reader.readAsDataURL(file[0]); + event.preventDefault(); + } else { + setImgError("Please check image size"); + } + } else { + setImgError("Invalid image type"); + } + }; + + // Function to check if an object is empty + const isEmpty = (object: any): boolean => { + + return true; + }; + + // Function to submit update operation + const submitUpdateEntity = async (values: EditEntityValues) => { + setLoading(true); + + const entityData = { + id: props?.entityData?.id, + name: values.name, + description: values.description, + logo: logoImage?.imagePreviewUrl as string || props?.entityData?.logoUrl, + + }; + + try { + if (props.isOrganization) { + const response = await updateOrganization(entityData, entityData.id?.toString() as string); + const { data } = response as AxiosResponse; + if (data?.statusCode === apiStatusCodes.API_STATUS_SUCCESS) { + if (props?.onEditSuccess) { + props?.onEditSuccess(); + } + props.setOpenModal(false); + } else { + setErrMsg(data?.message as string); + } + } else { + const response = await updateEcosystem(entityData); + const { data } = response as AxiosResponse; + console.log('data::', data); + if (data?.statusCode === apiStatusCodes.API_STATUS_SUCCESS) { + if (props?.onEditSuccess) { + props?.onEditSuccess(); + } + props.setOpenModal(false); + } else { + setErrMsg(data?.message as string); + } + } + } catch (error) { + console.error("An error occurred:", error); + setLoading(false); + } + }; + console.log(6566, initialEntityData) + + return ( + { + setLogoImage({ + logoFile: "", + imagePreviewUrl: "", + fileName: '' + }); + setInitialEntityData(initialEntityData); + props.setOpenModal(false); + }}> + Edit {props.isOrganization ? "Organization" : "Ecosystem"} + + { + setErrMsg(null); + }} + /> + + ) => { + await submitUpdateEntity(values); + + window.location.reload(); + + }} + > + {(formikHandlers): JSX.Element => ( +
+
+
+ {isImageEmpty ? ( + + ) : ( + {`${props.isOrganization + )} +
+

+ {props.isOrganization ? "Organization Logo" : "Ecosystem Logo"} +

+
+ JPG, JPEG and PNG. Max size of 1MB +
+
+
+ +
+
+
+
+
+
+
+
+ + {formikHandlers?.errors?.name && formikHandlers?.touched?.name && ( + {formikHandlers?.errors?.name} + )} +
+
+
+
+ + {formikHandlers?.errors?.description && formikHandlers?.touched?.description && ( + {formikHandlers?.errors?.description} + )} +
+ +
+ )} +
+
+
+ ); +}; + +export default EditPopupModal; diff --git a/src/components/organization/interfaces/index.ts b/src/components/organization/interfaces/index.ts index 3dd8dd250..e685c5560 100644 --- a/src/components/organization/interfaces/index.ts +++ b/src/components/organization/interfaces/index.ts @@ -7,6 +7,7 @@ export interface UserOrgRole { } export interface Organisation { + logoFile: string id: number createDateTime: string createdBy: number @@ -20,6 +21,7 @@ export interface Organisation { userOrgRoles: UserOrgRole[] org_agents: OrgAgent[] publicProfile: boolean + } export interface OrgRole { diff --git a/src/components/organization/invitations/SendInvitationModal.tsx b/src/components/organization/invitations/SendInvitationModal.tsx index e4a34ea44..1d63f0c82 100644 --- a/src/components/organization/invitations/SendInvitationModal.tsx +++ b/src/components/organization/invitations/SendInvitationModal.tsx @@ -153,7 +153,7 @@ const SendInvitationModal = (props: { { setErrMsg(null); }} @@ -236,7 +236,7 @@ const SendInvitationModal = (props: {
    {invitations.map((invitation) => ( -
  • +