implement progress steps component
This commit is contained in:
parent
8822d479a0
commit
bc1a072515
9 changed files with 318 additions and 73 deletions
|
|
@ -26,7 +26,7 @@ export const Select = ({ control, name, label, options, disabled = false }: Sele
|
|||
value={field.value ? field.value : ''} // input value
|
||||
name={name} // send down the input name
|
||||
ref={field.ref} // send input ref, so we can focus on input when error appear
|
||||
className="shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md"
|
||||
className="block shadow-sm focus:ring-primary-500 focus:border-primary-500 block w-full sm:text-sm border-gray-300 rounded-md"
|
||||
disabled={disabled}
|
||||
>
|
||||
{options?.map((option) => (
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ export const Modal: React.FC<ModalProps> = ({
|
|||
useCancelButton = false,
|
||||
isLoading = false,
|
||||
leftActions = <></>,
|
||||
saveButtonDisabled = false,
|
||||
}) => {
|
||||
const cancelButtonRef = useRef(null);
|
||||
const saveButtonRef = useRef(null);
|
||||
|
|
@ -86,9 +87,12 @@ export const Modal: React.FC<ModalProps> = ({
|
|||
<div className="ml-auto sm:flex sm:flex-row-reverse">
|
||||
<button
|
||||
type="button"
|
||||
className="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-primary-600 text-base font-medium text-white hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 sm:ml-3 sm:w-auto sm:text-sm"
|
||||
className={`w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-primary-600 text-base font-medium text-white hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 sm:ml-3 sm:w-auto sm:text-sm ${
|
||||
saveButtonDisabled ? 'opacity-50' : ''
|
||||
}`}
|
||||
onClick={onSave}
|
||||
ref={saveButtonRef}
|
||||
disabled={saveButtonDisabled}
|
||||
>
|
||||
Save Changes
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -8,4 +8,5 @@ export type ModalProps = {
|
|||
useCancelButton?: boolean;
|
||||
isLoading?: boolean;
|
||||
leftActions?: React.ReactNode;
|
||||
saveButtonDisabled?: boolean;
|
||||
};
|
||||
|
|
|
|||
107
src/components/Steps/ProgressSteps.tsx
Normal file
107
src/components/Steps/ProgressSteps.tsx
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
import _ from 'lodash';
|
||||
import React from 'react';
|
||||
import { ProgressStepsProps, ProgressStepStatus } from './types';
|
||||
|
||||
export const ProgressSteps: React.FC<ProgressStepsProps> = ({ steps, onNext, onPrevious, onStepClick, children }) => {
|
||||
const handleNext = () => {
|
||||
if (onNext) {
|
||||
onNext();
|
||||
}
|
||||
};
|
||||
const handlePrevious = () => {
|
||||
if (onPrevious) {
|
||||
onPrevious();
|
||||
}
|
||||
};
|
||||
|
||||
const showNextPage = () => {
|
||||
if (onNext) {
|
||||
return _.some(steps, { status: ProgressStepStatus.Upcoming });
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const showPreviousPage = () => {
|
||||
if (onPrevious) {
|
||||
return _.some(steps, { status: ProgressStepStatus.Complete });
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const handleStepClick = (stepId: string) => {
|
||||
if (onStepClick) {
|
||||
onStepClick(stepId);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<nav aria-label="Progress">
|
||||
{/* eslint-disable-next-line jsx-a11y/no-redundant-roles */}
|
||||
<ol role="list" className="space-y-4 md:flex md:space-y-0 md:space-x-8 mb-4">
|
||||
{steps.map((step) => (
|
||||
<li key={step.name} className="md:flex-1" onClick={() => handleStepClick(step.id)}>
|
||||
{step.status === ProgressStepStatus.Complete ? (
|
||||
<a
|
||||
href={step.href}
|
||||
className="group pl-4 py-2 flex flex-col border-l-4 border-primary-500 md:pl-0 md:pb-0 md:border-l-0 md:border-t-4"
|
||||
>
|
||||
<span className="text-xs text-primary-600 font-semibold tracking-wide uppercase group-hover:text-primary-800">
|
||||
{step.id}
|
||||
</span>
|
||||
<span className="text-sm font-medium">{step.name}</span>
|
||||
</a>
|
||||
) : step.status === ProgressStepStatus.Current ? (
|
||||
<a
|
||||
href={step.href}
|
||||
className="pl-4 py-2 flex flex-col border-l-4 border-primary-500 md:pl-0 md:pb-0 md:border-l-0 md:border-t-4"
|
||||
aria-current="step"
|
||||
>
|
||||
<span className="text-xs text-primary-600 font-semibold tracking-wide uppercase">{step.id}</span>
|
||||
<span className="text-sm font-medium">{step.name}</span>
|
||||
</a>
|
||||
) : (
|
||||
<a
|
||||
href={step.href}
|
||||
className="group pl-4 py-2 flex flex-col border-l-4 border-gray-200 hover:border-gray-300 md:pl-0 md:pb-0 md:border-l-0 md:border-t-4"
|
||||
>
|
||||
<span className="text-xs text-gray-500 font-semibold tracking-wide uppercase group-hover:text-gray-700">
|
||||
{step.id}
|
||||
</span>
|
||||
<span className="text-sm font-medium">{step.name}</span>
|
||||
</a>
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
{children}
|
||||
|
||||
{(showNextPage() || showPreviousPage()) && (
|
||||
<div className="pt-4 sm sm:flex">
|
||||
<div className="ml-auto sm:flex sm:flex-row-reverse">
|
||||
{showNextPage() && (
|
||||
<button
|
||||
type="button"
|
||||
className="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-primary-600 text-base font-medium text-white hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 sm:ml-3 sm:w-auto sm:text-sm"
|
||||
onClick={handleNext}
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
)}
|
||||
{showPreviousPage() && (
|
||||
<button
|
||||
type="button"
|
||||
className="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-primary-600 text-base font-medium text-white hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 sm:ml-3 sm:w-auto sm:text-sm"
|
||||
onClick={handlePrevious}
|
||||
>
|
||||
Previous
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
1
src/components/Steps/index.ts
Normal file
1
src/components/Steps/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { ProgressSteps } from './ProgressSteps';
|
||||
20
src/components/Steps/types.ts
Normal file
20
src/components/Steps/types.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
export type ProgressStepsProps = {
|
||||
steps: ProgressStepInfo[];
|
||||
onNext?: () => void;
|
||||
onPrevious?: () => void;
|
||||
onStepClick?: (stepId: string) => void;
|
||||
};
|
||||
|
||||
export interface ProgressStepInfo {
|
||||
id: string;
|
||||
name: string;
|
||||
status: ProgressStepStatus;
|
||||
component?: React.ReactNode;
|
||||
href?: string;
|
||||
}
|
||||
|
||||
export enum ProgressStepStatus {
|
||||
Complete = 0,
|
||||
Current = 1,
|
||||
Upcoming = 2,
|
||||
}
|
||||
|
|
@ -24,12 +24,12 @@ export const appAccessList = [
|
|||
];
|
||||
|
||||
export const allAppAccessList = [
|
||||
...appAccessList,
|
||||
{
|
||||
name: 'dashboard',
|
||||
image: '/assets/logo-small.svg',
|
||||
label: 'Dashboard',
|
||||
},
|
||||
...appAccessList,
|
||||
];
|
||||
|
||||
export const initialAppRoles = [
|
||||
|
|
|
|||
|
|
@ -5,3 +5,4 @@ export { Banner } from './Banner';
|
|||
export { Tabs } from './Tabs';
|
||||
export { Modal, ConfirmationModal } from './Modal';
|
||||
export { UserModal } from './UserModal';
|
||||
export { ProgressSteps } from './Steps';
|
||||
|
|
|
|||
Reference in a new issue