Skip to content

Commit

Permalink
added components for process creation; use them on multiple occasions
Browse files Browse the repository at this point in the history
  • Loading branch information
LucasMGo committed Oct 19, 2023
1 parent a351daa commit 1a17c07
Show file tree
Hide file tree
Showing 7 changed files with 459 additions and 226 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import useModelerStateStore from '@/lib/use-modeler-state-store';
import { createNewProcessVersion } from '@/lib/helpers/processVersioning';
import VersionCreationButton from '@/components/version-creation-button';
import Auth from '@/lib/AuthCanWrapper';
import ProcessCreationButton from '@/components/process-creation-button';

type ProcessProps = {
params: { processId: string };
Expand Down Expand Up @@ -75,10 +76,6 @@ const Processes: FC<ProcessProps> = () => {
}
}, [minimized]);

const createProcess = () => {
console.log('create process');
};

const createProcessVersion = async (values: {
versionName: string;
versionDescription: string;
Expand Down Expand Up @@ -119,9 +116,9 @@ const Processes: FC<ProcessProps> = () => {
{menu}
<Divider style={{ margin: '4px 0' }} />
<Space style={{ display: 'flex', justifyContent: 'center' }}>
<Button type="text" icon={<PlusOutlined />} onClick={createProcess}>
<ProcessCreationButton type="text" icon={<PlusOutlined />}>
Create new process
</Button>
</ProcessCreationButton>
</Space>
</>
)}
Expand Down
74 changes: 74 additions & 0 deletions src/management-system-v2/components/ProcessSider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
'use client';

import { FC, PropsWithChildren } from 'react';
import { Menu } from 'antd';
const { SubMenu, Item, ItemGroup } = Menu;
import { EditOutlined, ProfileOutlined, FileAddOutlined, StarOutlined } from '@ant-design/icons';
import { usePathname, useRouter } from 'next/navigation';
import { useAuthStore } from '@/lib/iam';
import ProcessCreationButton from './process-creation-button';

const ProcessSider: FC<PropsWithChildren> = () => {
const router = useRouter();
const activeSegment = usePathname().slice(1) || 'processes';
const ability = useAuthStore((state) => state.ability);

return (
<>
<ItemGroup key="processes" title="Processes">
{ability.can('view', 'Process') ? (
<SubMenu
key="processes"
title={
<span
onClick={() => {
router.push(`/processes`);
}}
>
Process List
</span>
}
className={activeSegment === 'processes' ? 'SelectedSegment' : ''}
icon={
<EditOutlined
onClick={() => {
router.push(`/processes`);
}}
/>
}
>
<Item
key="newProcess"
icon={<FileAddOutlined />}
hidden={!ability.can('create', 'Process')}
>
<ProcessCreationButton
wrapperElement={<span>New Process</span>}
></ProcessCreationButton>
</Item>
<Item key="processFavorites" icon={<StarOutlined />}>
Favorites
</Item>
</SubMenu>
) : null}

{ability.can('view', 'Template') ? (
<SubMenu key="templates" title="Templates" icon={<ProfileOutlined />}>
<Item
key="newTemplate"
icon={<FileAddOutlined />}
hidden={!ability.can('create', 'Template')}
>
New Template
</Item>
<Item key="templateFavorites" icon={<StarOutlined />}>
Favorites
</Item>
</SubMenu>
) : null}
</ItemGroup>
</>
);
};

export default ProcessSider;
102 changes: 7 additions & 95 deletions src/management-system-v2/components/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,15 @@

import styles from './layout.module.scss';
import { FC, PropsWithChildren, useState } from 'react';
import { Layout as AntLayout, Grid, Menu, MenuProps } from 'antd';
const { SubMenu, Item, Divider, ItemGroup } = Menu;
import Logo from '@/public/proceed.svg';
import {
EditOutlined,
UnorderedListOutlined,
ProfileOutlined,
FileAddOutlined,
SettingOutlined,
ApiOutlined,
UserOutlined,
StarOutlined,
UnlockOutlined,
} from '@ant-design/icons';
import { Layout as AntLayout, Grid, Menu } from 'antd';
const { Item, Divider, ItemGroup } = Menu;
import { SettingOutlined, ApiOutlined, UserOutlined, UnlockOutlined } from '@ant-design/icons';
import Image from 'next/image';
import { usePathname, useRouter } from 'next/navigation';
import { usePathname } from 'next/navigation';
import cn from 'classnames';
import { useAuthStore } from '@/lib/iam';
import Link from 'next/link';

const items: MenuProps['items'] = [
{
key: 'processes',
icon: <EditOutlined />,
label: 'Processes',
},
{
key: 'projects',
icon: <UnorderedListOutlined />,
label: 'Projects',
},
{
key: 'templates',
icon: <ProfileOutlined />,
label: 'Templates',
disabled: true,
},
];
import ProcessSider from './ProcessSider';

/**
* The main layout of the application. It defines the sidebar and footer. Note
Expand All @@ -51,7 +22,6 @@ const items: MenuProps['items'] = [
* page content in parallel routes.
*/
const Layout: FC<PropsWithChildren> = ({ children }) => {
const router = useRouter();
const activeSegment = usePathname().slice(1) || 'processes';
const [collapsed, setCollapsed] = useState(false);
const ability = useAuthStore((state) => state.ability);
Expand Down Expand Up @@ -88,68 +58,10 @@ const Layout: FC<PropsWithChildren> = ({ children }) => {
</Link>
</div>
{loggedIn ? (
<Menu
theme="light"
mode="inline"
selectedKeys={[activeSegment]}
onClick={({ key }) => {
const path = key.split(':').at(-1);
router.push(`/${path}`);
}}
>
<Menu theme="light" mode="inline" selectedKeys={[activeSegment]}>
{ability.can('view', 'Process') || ability.can('view', 'Template') ? (
<>
<ItemGroup key="processes" title="Processes">
{ability.can('view', 'Process') ? (
<SubMenu
key="processes"
title={
<span
onClick={() => {
router.push(`/processes`);
}}
>
Process List
</span>
}
className={activeSegment === 'processes' ? 'SelectedSegment' : ''}
icon={
<EditOutlined
onClick={() => {
router.push(`/processes`);
}}
/>
}
>
<Item
key="newProcess"
icon={<FileAddOutlined />}
hidden={!ability.can('create', 'Process')}
>
New Process
</Item>
<Item key="processFavorites" icon={<StarOutlined />}>
Favorites
</Item>
</SubMenu>
) : null}

{ability.can('view', 'Template') ? (
<SubMenu key="templates" title="Templates" icon={<ProfileOutlined />}>
<Item
key="newTemplate"
icon={<FileAddOutlined />}
hidden={!ability.can('create', 'Template')}
>
New Template
</Item>
<Item key="templateFavorites" icon={<StarOutlined />}>
Favorites
</Item>
</SubMenu>
) : null}
</ItemGroup>

<ProcessSider></ProcessSider>
<Divider />
</>
) : null}
Expand Down
72 changes: 72 additions & 0 deletions src/management-system-v2/components/process-creation-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
'use client';

import React, { ReactNode, useState } from 'react';

import { Button } from 'antd';
import type { ButtonProps } from 'antd';
import ProcessModal from './process-modal';
import { usePostAsset } from '@/lib/fetch-data';
import { createProcess } from '@/lib/helpers/processHelpers';

type ProcessCreationButtonProps = ButtonProps & {
createProcess?: (values: { name: string; description: string }) => any;
wrapperElement?: ReactNode;
};

/**
*
* Button to create Processes including a Modal for inserting needed values. Alternatively, a custom wrapper element can be used instead of a button.
* Custom function for creation of process using inserted values can be applied
*/
const ProcessCreationButton: React.FC<ProcessCreationButtonProps> = ({
createProcess: customCreateProcess,
wrapperElement,
...props
}) => {
const [isProcessModalOpen, setIsProcessModalOpen] = useState(false);
const { mutateAsync: postProcess } = usePostAsset('/process');

const createNewProcess = async (values: { name: string; description: string }) => {
const { metaInfo, bpmn } = await createProcess(values);
try {
await postProcess({
body: { bpmn: bpmn, departments: [] },
});
} catch (err) {
console.log(err);
}
};

return (
<>
{wrapperElement ? (
<div
onClick={() => {
setIsProcessModalOpen(true);
}}
>
{wrapperElement}
</div>
) : (
<Button
{...props}
onClick={() => {
setIsProcessModalOpen(true);
}}
></Button>
)}
<ProcessModal
close={(values) => {
setIsProcessModalOpen(false);

if (values) {
customCreateProcess ? customCreateProcess(values) : createNewProcess(values);
}
}}
show={isProcessModalOpen}
></ProcessModal>
</>
);
};

export default ProcessCreationButton;
90 changes: 90 additions & 0 deletions src/management-system-v2/components/process-modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
'use client';

import React, { useState } from 'react';

import { Button, Modal, Form, Input } from 'antd';

import { FormInstance } from 'antd/es/form';

const ModalSubmitButton = ({ form, onSubmit }: { form: FormInstance; onSubmit: Function }) => {
const [submittable, setSubmittable] = useState(false);

// Watch all values
const values = Form.useWatch([], form);

React.useEffect(() => {
form.validateFields({ validateOnly: true }).then(
() => {
setSubmittable(true);
},
() => {
setSubmittable(false);
},
);
}, [form, values]);

return (
<Button
type="primary"
htmlType="submit"
disabled={!submittable}
onClick={() => {
onSubmit(values);
form.resetFields();
}}
>
Create Process
</Button>
);
};

type ProcessModalProps = {
show: boolean;
close: (values?: { name: string; description: string }) => void;
};
const ProcessModal: React.FC<ProcessModalProps> = ({ show, close }) => {
const [form] = Form.useForm();

return (
<Modal
title="Create new Process"
open={show}
onCancel={() => {
close();
}}
footer={[
<Button
key="cancel"
onClick={() => {
close();
}}
>
Cancel
</Button>,
<ModalSubmitButton key="submit" form={form} onSubmit={close}></ModalSubmitButton>,
]}
>
<Form form={form} name="name" wrapperCol={{ span: 24 }} autoComplete="off">
<Form.Item
name="name"
rules={[{ required: true, message: 'Please input the Process Name!' }]}
>
<Input placeholder="Process Name" />
</Form.Item>
<Form.Item
name="description"
rules={[{ required: true, message: 'Please input the Process Description!' }]}
>
<Input.TextArea
showCount
maxLength={150}
style={{ height: 100 }}
placeholder="Process Description"
/>
</Form.Item>
</Form>
</Modal>
);
};

export default ProcessModal;
Loading

0 comments on commit 1a17c07

Please sign in to comment.