Skip to content

Commit

Permalink
372 engagement modal (#379)
Browse files Browse the repository at this point in the history
  • Loading branch information
mathildehaugum authored Dec 8, 2023
1 parent a7f762b commit 01a4386
Show file tree
Hide file tree
Showing 10 changed files with 184 additions and 98 deletions.
19 changes: 12 additions & 7 deletions frontend/src/components/Buttons/ActionButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,18 @@ export default function ActionButton({
}: ActionButtonProps) {
const variantClass =
{
primary: "bg-primary text-white hover:bg-primary_darker",
secondary:
"bg-white text-primary border border-primary/50 hover:bg-primary/10 hover:border-primary",
terniary: "bg-white text-primary hover:bg-primary/10",
primary: `bg-primary text-white ${
!disabled && "hover:bg-primary_darker"
}`,
secondary: `bg-white text-primary border border-primary/50 ${
!disabled && "hover:border-primary"
}`,
terniary: `bg-white text-primary ${
!disabled && "hover:bg-primary/10 hover:bg-primary/10"
}`,
}[variant] ?? "Default";

const disabledClass = disabled ? "bg-opacity-50" : "";
const disabledClass = disabled ? "bg-opacity-50 cursor-default" : "";
const fullWidthClass = fullWidth ? "w-full" : "";
const buttonShapeClass = iconBtn
? small
Expand All @@ -47,8 +52,8 @@ export default function ActionButton({

return (
<BaseButton
className={` ${variantClass} ${disabledClass} ${fullWidthClass} ${buttonShapeClass} ${className}`}
onClick={onClick}
className={`${variantClass} ${disabledClass} ${fullWidthClass} ${buttonShapeClass} ${className}`}
onClick={() => !disabled && onClick}
type={type}
>
<IconBox small={small}>{iconLeft}</IconBox>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import React from "react";
import { FilteredContext } from "@/hooks/ConsultantFilterProvider";
import { useContext } from "react";
import Select, { MultiValue } from "react-select";

export type SelectOption = { value: string; label: string };

export default function ReactSelect({
export default function ComboBox({
options,
selectedSingleOptionValue,
selectedMultipleOptionsValue,
onSingleOptionChange,
onMultipleOptionsChange,
isMultipleOptions = false,
isDisabled = false,
placeHolderText = "Velg...",
isClearable = false,
}: {
options: SelectOption[];
Expand All @@ -18,12 +21,20 @@ export default function ReactSelect({
onSingleOptionChange?: (arg: SelectOption) => void;
onMultipleOptionsChange?: (arg: MultiValue<SelectOption>) => void;
isMultipleOptions?: boolean;
isDisabled?: boolean;
placeHolderText?: string;
isClearable?: boolean;
}) {
const { setCloseModalOnBackdropClick } = useContext(FilteredContext);

return (
<Select
onFocus={() => setCloseModalOnBackdropClick(false)}
onBlur={() => setCloseModalOnBackdropClick(true)}
placeholder={placeHolderText}
isMulti={isMultipleOptions}
options={options}
isDisabled={isDisabled}
isClearable={isClearable}
value={
isMultipleOptions
Expand All @@ -35,7 +46,24 @@ export default function ReactSelect({
? onMultipleOptionsChange?.(a as MultiValue<SelectOption>)
: onSingleOptionChange?.(a as SelectOption);
}}
classNames={{ menu: () => "bg-white overflow-hidden" }}
styles={{
valueContainer: (base) => ({
...base,
overflowX: "scroll",
flexWrap: "unset",
"::-webkit-scrollbar": {
display: "none",
},
}),
multiValue: (base) => ({
...base,
flex:
selectedMultipleOptionsValue?.length &&
selectedMultipleOptionsValue?.length >= 2
? "1 0 auto"
: "",
}),
}}
/>
);
}
5 changes: 4 additions & 1 deletion frontend/src/components/Modals/BaseModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ function BaseModal(props: BaseModalProps) {
const { children, modalRef, classNames } = props;

return (
<dialog ref={modalRef} className={`rounded-lg p-4 ${classNames}`}>
<dialog
ref={modalRef}
className={`rounded-lg p-4 overflow-visible ${classNames}`}
>
{children}
</dialog>
);
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/Staffing/AddConsultantCell.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { ReactElement, useState } from "react";
import { Plus } from "react-feather";
import { SelectOption } from "@/components/ReactSelect";
import { SelectOption } from "@/components/ComboBox";
import { useModal } from "@/hooks/useModal";

import { Consultant } from "@/types";
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/Staffing/AddConsultantModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Consultant } from "@/types";
import { RefObject, ReactElement, useState, FormEvent } from "react";
import ActionButton from "../Buttons/ActionButton";
import EasyModal from "../Modals/EasyModal";
import ReactSelect, { SelectOption } from "../ReactSelect";
import ComboBox, { SelectOption } from "../ComboBox";

interface AddConsultantModalProps {
closeConsultantModal: () => void;
Expand Down Expand Up @@ -50,7 +50,7 @@ export function AddConsultantModal(
>
<form onSubmit={handleSubmit}>
<div className="flex flex-col gap-6 pt-6 h-32">
<ReactSelect
<ComboBox
options={consultantOptions}
selectedSingleOptionValue={selectedConsultant}
onSingleOptionChange={setSelectedConsultant}
Expand Down
193 changes: 114 additions & 79 deletions frontend/src/components/Staffing/AddEngagementForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ import React, {
} from "react";
import { useModal } from "@/hooks/useModal";
import { FilteredContext } from "@/hooks/ConsultantFilterProvider";
import ReactSelect, { SelectOption } from "@/components/ReactSelect";
import ComboBox, { SelectOption } from "@/components/ComboBox";
import { MultiValue } from "react-select";
import EasyModal from "@/components/Modals/EasyModal";
import { AddEngagementHoursModal } from "@/components/Staffing/AddEngagementHoursModal";
import {
Consultant,
EngagementWriteModel,
ProjectState,
ProjectWithCustomerModel,
Expand All @@ -22,12 +23,15 @@ import ActionButton from "../Buttons/ActionButton";
export function AddEngagementForm({
closeEngagementModal,
easyModalRef,
consultant,
}: {
closeEngagementModal: () => void;
easyModalRef: RefObject<HTMLDialogElement>;
consultant: Consultant;
}) {
const { closeModalOnBackdropClick } = useContext(FilteredContext);
const { openModal, modalRef } = useModal({
closeOnBackdropClick: false,
closeOnBackdropClick: closeModalOnBackdropClick,
});
const { customers, consultants, setIsDisabledHotkeys } =
useContext(FilteredContext);
Expand All @@ -40,8 +44,13 @@ export function AddEngagementForm({
const [selectedEngagement, setSelectedEngagement] =
useState<SelectOption | null>(null);

const selectedConsultant: SelectOption = {
value: consultant.id.toString(),
label: consultant.name,
};

const [selectedConsultants, setSelectedConsultants] =
useState<MultiValue<SelectOption> | null>(null);
useState<MultiValue<SelectOption> | null>([selectedConsultant]);

const [project, setProject] = useState<
ProjectWithCustomerModel | undefined
Expand Down Expand Up @@ -79,7 +88,7 @@ export function AddEngagementForm({
const [radioValue, setRadioValue] = useState(ProjectState.Offer);

// State for toggle
const [isFakturerbar, setIsFakturerbar] = useState(false);
const [isFakturerbar, setIsFakturerbar] = useState(true);

// Handler for select components
function handleSelectedCustomerChange(newCustomer: SelectOption) {
Expand Down Expand Up @@ -131,12 +140,8 @@ export function AddEngagementForm({
isBillable: isFakturerbar,
};

console.log(body);

const result = await submitAddEngagementForm(body);

console.log(result);

// TODO: This is a simplified mockup.
if (result) {
setProject(result);
Expand All @@ -149,89 +154,119 @@ export function AddEngagementForm({
// TODO: #370 - Error handling for snackbars here
}

function resetSelectedValues() {
setSelectedCustomer(null);
setSelectedEngagement(null);
setSelectedConsultants([selectedConsultant]);
setRadioValue(ProjectState.Offer);
setIsFakturerbar(false);
}

return (
<>
<EasyModal
modalRef={easyModalRef}
title={"Legg til engasjement"}
showCloseButton={true}
onClose={() => setIsDisabledHotkeys(false)}
onClose={() => {
setIsDisabledHotkeys(false);
resetSelectedValues();
}}
>
<div className="min-h-[300px]">
<form onSubmit={handleSubmit}>
<div className="flex flex-col gap-6 pt-6 h-96">
{/* Selected Customer */}
<div className="flex flex-col gap-2">
<p className="small text-black">Konsulenter</p>
<ReactSelect
options={consultantOptions}
selectedMultipleOptionsValue={selectedConsultants}
onMultipleOptionsChange={setSelectedConsultants}
isMultipleOptions={true}
/>
</div>
<div className="flex flex-col gap-2">
<p className="small text-black">Kunde</p>
<ReactSelect
options={customerOptions}
selectedSingleOptionValue={selectedCustomer}
onSingleOptionChange={handleSelectedCustomerChange}
isMultipleOptions={false}
<form
onSubmit={() => selectedEngagement == null && handleSubmit}
className="h-full flex flex-col gap-6"
>
<div className="flex flex-col gap-6 pt-6">
{/* Selected Customer */}
<div className="flex flex-col gap-2">
<p className="small text-black">Konsulenter</p>
<ComboBox
options={consultantOptions}
selectedMultipleOptionsValue={selectedConsultants}
onMultipleOptionsChange={setSelectedConsultants}
isMultipleOptions={true}
placeHolderText="Velg konsulenter"
/>
</div>
<div className="flex flex-col gap-2">
<p className="small text-black">Kunde</p>
<ComboBox
options={customerOptions}
selectedSingleOptionValue={selectedCustomer}
onSingleOptionChange={handleSelectedCustomerChange}
isMultipleOptions={false}
placeHolderText="Velg kunde"
isDisabled={!selectedConsultants}
/>
</div>
<div className="flex flex-col gap-2">
<p className="small text-black">Engasjement</p>
<ComboBox
options={projectOptions}
onSingleOptionChange={handleSelectedEngagementChange}
selectedSingleOptionValue={selectedEngagement}
isMultipleOptions={false}
placeHolderText="Velg engasjement"
isDisabled={selectedCustomer == null}
/>
</div>
{/* Radio Button Group */}
<div
className={`flex flex-row gap-4 ${
selectedEngagement == null && "hidden"
}`}
>
<label className="flex gap-2 normal items-center">
<input
type="radio"
value={ProjectState.Offer}
checked={radioValue === ProjectState.Offer}
onChange={handleRadioChange}
/>
</div>
<div className="flex flex-col gap-2">
<p className="small text-black">Engasjement</p>
<ReactSelect
options={projectOptions}
onSingleOptionChange={handleSelectedEngagementChange}
selectedSingleOptionValue={selectedEngagement}
isMultipleOptions={false}
Tilbud
</label>
<label className="flex gap-2 normal items-center">
<input
type="radio"
value={ProjectState.Order}
checked={radioValue === ProjectState.Order}
onChange={handleRadioChange}
/>
</div>
{/* Radio Button Group */}
<div className="flex flex-row gap-4">
<label className="flex gap-2 normal items-center">
<input
type="radio"
value={ProjectState.Offer}
checked={radioValue === ProjectState.Offer}
onChange={handleRadioChange}
/>
Tilbud
</label>
<label className="flex gap-2 normal items-center">
<input
type="radio"
value={ProjectState.Order}
checked={radioValue === ProjectState.Order}
onChange={handleRadioChange}
/>
Ordre
</label>
</div>
{/* Toggle (Checkbox) */}
<label className="flex flex-row justify-between items-center">
Fakturerbart
<div
className={`rounded-full w-[52px] h-7 flex items-center ${
isFakturerbar ? "bg-primary" : "bg-black/20"
}`}
onClick={handleToggleChange}
>
<div
className={`m-[2px] bg-white rounded-full w-6 h-6 ${
isFakturerbar && " translate-x-6"
}`}
></div>
</div>
Ordre
</label>
</div>
{/* Toggle (Checkbox) */}
<label
className={`flex flex-row justify-between items-center normal ${
selectedEngagement == null && "hidden"
}`}
>
Fakturerbart
<div
className={`rounded-full w-[52px] h-7 flex items-center ${
isFakturerbar ? "bg-primary" : "bg-black/20"
}`}
onClick={handleToggleChange}
>
<div
className={`m-[2px] bg-white rounded-full w-6 h-6 ${
isFakturerbar && " translate-x-6"
}`}
></div>
</div>
</label>
</div>

<ActionButton variant="primary" fullWidth type="submit">
Legg til engasjement
</ActionButton>
</form>
</div>
<ActionButton
variant="primary"
fullWidth
type="submit"
disabled={selectedEngagement == null}
>
Legg til engasjement
</ActionButton>
</form>
</EasyModal>
<AddEngagementHoursModal
modalRef={modalRef}
Expand Down
Loading

0 comments on commit 01a4386

Please sign in to comment.