Skip to content

Commit

Permalink
Merge pull request #3 from credebl/create-organization-flow
Browse files Browse the repository at this point in the history
Create organization flow: 172
  • Loading branch information
makrandshinde committed Jul 7, 2023
2 parents a6370ae + 80b89ac commit fcc7997
Show file tree
Hide file tree
Showing 11 changed files with 456 additions and 11 deletions.
8 changes: 4 additions & 4 deletions src/app/SideBar.astro
Original file line number Diff line number Diff line change
Expand Up @@ -128,28 +128,28 @@ import { url } from '../lib/data.js';
<ul id="dropdown-layouts" class="hidden py-2 space-y-2">
<li>
<a
href={url('orgs')}
href={url('organizations')}
class="flex items-center p-2 text-base text-gray-900 transition duration-75 rounded-lg pl-11 group hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-700"
>Organizations</a
>
</li>
<li>
<a
href={url('orgs/users')}
href={url('organizations/users')}
class="flex items-center p-2 text-base text-gray-900 transition duration-75 rounded-lg pl-11 group hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-700"
>Users</a
>
</li>
<li>
<a
href={url('orgs/schemas')}
href={url('organizations/schemas')}
class="flex items-center p-2 text-base text-gray-900 transition duration-75 rounded-lg pl-11 group hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-700"
>Schemas</a
>
</li>
<li>
<a
href={url('orgs/credentials')}
href={url('organizations/credentials')}
class="flex items-center p-2 text-base text-gray-900 transition duration-75 rounded-lg pl-11 group hover:bg-gray-100 dark:text-gray-200 dark:hover:bg-gray-700"
>Credentials</a
>
Expand Down
13 changes: 8 additions & 5 deletions src/components/Authentication/SignInUser.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import * as yup from 'yup';

import { Button, Checkbox, Label, TextInput } from 'flowbite-react';
import {
Field,
Form,
Expand All @@ -6,11 +9,10 @@ import {
FormikProps,
FormikValues,
} from 'formik';
import { Button, Checkbox, Label, TextInput } from 'flowbite-react';
import * as yup from 'yup';
import { Alert } from 'flowbite-react';
import { useEffect, useState } from 'react';
import { UserSignInData, loginUser, passwordEncryption } from '../../api/Auth';
import { useEffect, useState } from 'react';

import { Alert } from 'flowbite-react';
import type { AxiosResponse } from 'axios';
import { apiStatusCodes } from '../../config/CommonConstant';

Expand Down Expand Up @@ -45,7 +47,8 @@ const SignInUser = () => {
setLoading(false)

if(data?.statusCode === apiStatusCodes.API_STATUS_SUCCESS){

localStorage.setItem('access_token', data?.data?.access_token);
window.location.href = '/dashboard'
}else{
setFailur(loginRsp as string)
}
Expand Down
43 changes: 43 additions & 0 deletions src/components/Dashboard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
'use client';

import { Button } from 'flowbite-react';
import CreateOrgFormModal from "./organization/CreateOrgFormModal.js";
import { useState } from 'react';

export default function Dashboard() {

const [openModal, setOpenModal] = useState<boolean>(false);
const props = { openModal, setOpenModal };

const createOrganizationModel = () => {
props.setOpenModal(true)
}

return (
<div className="px-4 pt-6">
<div>
<div
className="p-4 bg-white border border-gray-200 rounded-lg shadow-sm 2xl:col-span-2 dark:border-gray-700 sm:p-6 dark:bg-gray-800"
>
<div className="flex items-center justify-center mb-4">
<Button
onClick={createOrganizationModel}
className='text-base font-medium text-center text-white bg-primary-700 rounded-lg hover:bg-primary-800 focus:ring-4 focus:ring-primary-300 sm:w-auto dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800"'
>
Create Organization
</Button>
</div>

{
props.openModal &&
<CreateOrgFormModal
openModal={props.openModal}
setOpenModal= {props.setOpenModal} />
}
</div>
</div>
</div>
)
}


276 changes: 276 additions & 0 deletions src/components/organization/CreateOrgFormModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
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 { useRef, useState } from "react";

import type { AxiosResponse } from 'axios';
import { asset } from '../../lib/data.js';
import { createOrganization } from "../../services/organization";

interface Values {
name: string;
description: string;
}

interface ILogoImage {
logoFile: string | File
imagePreviewUrl: string | ArrayBuffer | null | File
}


const CreateOrgFormModal = (props: { openModal: boolean; setOpenModal: (flag: boolean) => void }) => {


const [logoImage, setLogoImage] = useState<ILogoImage>({
logoFile: "",
imagePreviewUrl: ""
})

const [loading, setLoading] = useState<boolean>(false)

const [isImageEmpty, setIsImageEmpty] = useState(true)
const [initialOrgData, setOrgData] = useState({
name: '',
description: '',
})
const [erroMsg, setErrMsg] = useState<string | null>(null)

const [imgError, setImgError] = useState('')


const ProcessImg = (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
})
}
}
}
}
}

const isEmpty = (object: any): boolean => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars, guard-for-in
for (const property in object) {
setIsImageEmpty(false)
return false
}
setIsImageEmpty(true)
return true
}


const handleImageChange = (event: any): void => {
setImgError('')
const reader = new FileReader()
const file = event?.target?.files
console.log(file);

const fieSize = 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 (fieSize <= imageSizeAccepted) {
reader.onloadend = (): void => {
ProcessImg(event)
isEmpty(reader.result)
}
reader.readAsDataURL(file[0])
event.preventDefault()
} else {
setImgError("Please check image size")
}
} else {
setImgError("Invalid image type")
}
}

return (
<Modal show={props.openModal === true} onClose={() => {
setLogoImage({
logoFile: "",
imagePreviewUrl: ""
})
setOrgData(initialOrgData)
props.setOpenModal(false)
}
}>
<Modal.Header>Create Organization</Modal.Header>
<Modal.Body>
<Formik
initialValues={initialOrgData}
validationSchema={
yup.object().shape({
name: yup
.string()
.min(2, 'Organization name must be at least 2 characters')
.max(50, 'Organization name must be at most 50 characters')
.required('Organization name is required')
.trim(),
description: yup
.string()
.min(2, 'Organization name must be at least 2 characters')
.max(255, 'Organization name must be at most 255 characters')
.required('Description is required')
})}
validateOnBlur
validateOnChange
enableReinitialize
onSubmit={async (
values: Values,
{ resetForm }: FormikHelpers<Values>
) => {

setLoading(true)

const orgData = {
name: values.name,
description: values.description,
logo: logoImage?.imagePreviewUrl as string || "",
website: ""
}

const resCreateOrg = await createOrganization(orgData)

const { data } = resCreateOrg as AxiosResponse
setLoading(false)

if (data?.statusCode === apiStatusCodes.API_STATUS_CREATED) {
alert(data?.message)
props.setOpenModal(false)

} else {
setErrMsg(resCreateOrg as string)
}

}}
>
{(formikHandlers): JSX.Element => (

<Form className="space-y-6" onSubmit={
formikHandlers.handleSubmit
}>
<div
className="mb-4 bg-white border border-gray-200 rounded-lg shadow-sm 2xl:col-span-2 dark:border-gray-700 sm:p-6 dark:bg-gray-800"
>
<div
className="items-center sm:flex xl:block 2xl:flex sm:space-x-4 xl:space-x-0 2xl:space-x-4"
>
{
typeof (logoImage.logoFile) === "string" ?
<Avatar
size="lg"
/> :
<img
className="mb-4 rounded-lg w-28 h-28 sm:mb-0 xl:mb-4 2xl:mb-0"
src={typeof (logoImage.logoFile) === "string" ? asset('images/users/bonnie-green-2x.png') : URL.createObjectURL(logoImage.logoFile)}
alt="Jese picture"
/>
}

<div>
<h3 className="mb-1 text-xl font-bold text-gray-900 dark:text-white">
Organization Logo
</h3>
<div className="mb-4 text-sm text-gray-500 dark:text-gray-400">
JPG, GIF or PNG. Max size of 1M
</div>
<div className="flex items-center space-x-4">


<div className="camera-btn">
<input type="file" accept="image/*" name="file" id="exampleFile1" title=""
onChange={(event): void => handleImageChange(event)} />
</div>

</div>
</div>
</div>
</div>
<div>
<div
className="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
>
<Label
htmlFor="name"
value="Name"
/>
</div>
<Field
id="name"
name="name"
value={formikHandlers.values.name}
required
className="bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500"
placeholder="OrgTech" />

</div>
<div>
<div
className="block mb-2 text-sm font-medium text-gray-900 dark:text-white"
>
<Label
htmlFor="description"
value="Description"
/>
</div>

<Field
id="description"
name="description"
value={formikHandlers.values.description}
as='textarea'
required
className="bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500"
placeholder="Description of your organization" />

</div>

<Button type="submit"
isProcessing={loading}

className='float-right text-base font-medium text-center text-white bg-primary-700 rounded-lg hover:bg-primary-800 focus:ring-4 focus:ring-primary-300 sm:w-auto dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800'
>
Create
</Button>
</Form>
)}

</Formik>
</Modal.Body>

</Modal>
)
}

export default CreateOrgFormModal;
Loading

0 comments on commit fcc7997

Please sign in to comment.