Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…icro-front-ends into Feature/FWF-3620-History-component
  • Loading branch information
Ajay-aot committed Oct 24, 2024
2 parents 9f7d071 + 5e6aaed commit ad37cf9
Show file tree
Hide file tree
Showing 23 changed files with 1,449 additions and 928 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ export const ConfirmModal: React.FC<ConfirmModalProps> = React.memo(({
<Modal
show={show}
onHide={onClose}
dialogClassName="modal-50w"
size="sm"
centered={true}
data-testid="confirm-modal"
aria-labelledby="confirm-modal-title"
aria-describedby="confirm-modal-message"
Expand All @@ -54,7 +55,7 @@ export const ConfirmModal: React.FC<ConfirmModalProps> = React.memo(({
<CloseIcon onClick={onClose} />
</div>
</Modal.Header>
<Modal.Body className="p-5">
<Modal.Body className="build-modal-body">
<div
className="d-flex flex-column"
id="confirm-modal-message"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ export const FormBuilderModal: React.FC<BuildFormModalProps> = React.memo(
<Modal
show={showBuildForm}
onHide={onClose}
dialogClassName="modal-50w"
size="sm"
centered={true}
>
<Modal.Header>
<Modal.Title>
Expand Down Expand Up @@ -120,7 +121,7 @@ export const FormBuilderModal: React.FC<BuildFormModalProps> = React.memo(
onChange={(event) => {
setFormDescription(event.target.value); // Set the description state
}}
minRows={5}
minRows={1}
/>
</Modal.Body>
<Modal.Footer className="d-flex justify-content-start">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Form, InputGroup } from 'react-bootstrap';
interface FormInputProps {
type?: string;
label?: string;
name? : string;
value?: string;
onChange?: (e: ChangeEvent<HTMLInputElement>) => void;
onBlur?: (e: FocusEvent<HTMLInputElement>) => void;
Expand All @@ -19,10 +20,12 @@ interface FormInputProps {
icon?: React.ReactNode;
id?: string;
onIconClick?: () => void;
onClick?: () => void;
}

export const FormInput: React.FC<FormInputProps> = ({
type = "text",
name,
label,
value ,
onChange,
Expand All @@ -38,13 +41,13 @@ export const FormInput: React.FC<FormInputProps> = ({
required = false,
icon,
id,
onIconClick
onIconClick,
onClick
}) => {

const inputClassNames = `form-control-input ${icon ? 'with-icon' : ''} ${className}`;

return (
<div className="form-input-box">
<Form.Group controlId={id}>
{label && (
<Form.Label className='custom-form-control-label'>
Expand All @@ -54,6 +57,7 @@ export const FormInput: React.FC<FormInputProps> = ({
<InputGroup className="custom-form-input-group">
<Form.Control
type={type}
name={name}
value={value}
onChange={onChange}
onBlur={onBlur}
Expand All @@ -66,10 +70,11 @@ export const FormInput: React.FC<FormInputProps> = ({
required={required}
className={inputClassNames}
onKeyDown={(e) => (e.keyCode === 13 && onIconClick())}
onClick={onClick}
/>
{icon && (
<InputGroup.Text
id="basic-addon1"
id="input-icon"
onClick={onIconClick}
className={disabled ? 'disabled-icon' : ''}>
{icon}
Expand All @@ -82,7 +87,6 @@ export const FormInput: React.FC<FormInputProps> = ({
)}
</InputGroup>
</Form.Group>
</div>
);
};

Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Form, InputGroup } from 'react-bootstrap';
interface FormTextAreaProps {
type?: string;
label?: string;
name?:string;
value?: string;
onChange?: (e: ChangeEvent<HTMLTextAreaElement>) => void;
onBlur?: (e: FocusEvent<HTMLTextAreaElement>) => void;
Expand All @@ -21,11 +22,13 @@ interface FormTextAreaProps {
minRows?: number;
onIconClick?: () => void;
maxRows?: number;
iconPosition?: string;
}

export const FormTextArea = forwardRef<HTMLTextAreaElement, FormTextAreaProps>(({
label,
value = '',
name,
onChange,
onBlur,
placeholder = '',
Expand All @@ -42,6 +45,7 @@ export const FormTextArea = forwardRef<HTMLTextAreaElement, FormTextAreaProps>((
minRows = 1,
onIconClick,
maxRows = 5,
iconPosition = "top"
}, ref) => {
const internalRef = useRef<HTMLTextAreaElement>(null);
const combinedRef = (ref || internalRef) as React.RefObject<HTMLTextAreaElement>;
Expand All @@ -60,8 +64,15 @@ export const FormTextArea = forwardRef<HTMLTextAreaElement, FormTextAreaProps>((
}
};

const getIconPositionClass = (position) => {
if (position === "top") return 'icon-top';
if (position === "center") return 'icon-center';
if (position === "bottom") return 'icon-bottom';
return 'icon-top';
};

const iconPositionClass = getIconPositionClass(iconPosition);
return (
<div className="form-input-box">
<Form.Group controlId={id}>
{label && (
<Form.Label className="custom-form-control-label">
Expand All @@ -72,6 +83,7 @@ export const FormTextArea = forwardRef<HTMLTextAreaElement, FormTextAreaProps>((
<Form.Control
as="textarea"
ref={combinedRef}
name={name}
value={value}
onChange={onChange}
onBlur={onBlur}
Expand All @@ -90,7 +102,7 @@ export const FormTextArea = forwardRef<HTMLTextAreaElement, FormTextAreaProps>((
<InputGroup.Text
id="basic-addon1"
onClick={onIconClick}
className={disabled ? 'disabled-icon' : ''}
className={`icon-wrapper ${iconPositionClass} ${disabled ? 'disabled-icon' : ''}`}
>
{icon}
</InputGroup.Text>
Expand All @@ -102,7 +114,6 @@ export const FormTextArea = forwardRef<HTMLTextAreaElement, FormTextAreaProps>((
)}
</InputGroup>
</Form.Group>
</div>
);
});

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import React, { useState, useRef, useEffect } from 'react';
import { InputGroup } from 'react-bootstrap';
import ListGroup from 'react-bootstrap/ListGroup';
import { FormInput } from './FormInput';
import { CloseIcon , ChevronIcon } from "../SvgIcons/index";


interface DropdownItem {
label: string;
onClick: () => void;
}
interface InputDropdownProps {
Options: DropdownItem[];
firstItemLabel: string;
dropdownLabel: string;
placeholder?: string;
isAllowInput: boolean;
required?: boolean;
value?: string;
selectedOption?: string;
feedback?: string;
ariaLabelforDropdown?:string
ariaLabelforInput?:string
dataTestIdforInput?:string
dataTestIdforDropdown?:string
setNewInput? : (value: string) => void;
isInvalid?: boolean;
}

export const InputDropdown: React.FC<InputDropdownProps> = ({
Options = [],
firstItemLabel,
dropdownLabel,
placeholder = '',
isAllowInput,
required = false,
selectedOption ,
feedback,
setNewInput,
ariaLabelforDropdown,
ariaLabelforInput,
dataTestIdforDropdown,
dataTestIdforInput,
isInvalid
}) => {
const [isDropdownOpen, setIsDropdownOpen] = useState<boolean>(false);
const [inputValue, setInputValue] = useState<string>(selectedOption || '');
const [filteredItems, setFilteredItems] = useState<DropdownItem[]>([]);
const [textBoxInput, setTextBoxInput] = useState<boolean>(false);

const dropdownRef = useRef<HTMLDivElement>(null);

const toggleDropdown = () => {
setIsDropdownOpen((prev) => !prev);
};

useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
setIsDropdownOpen(false);
}
};

document.addEventListener('mousedown', handleClickOutside);
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}, [dropdownRef]);

useEffect(() => {
if (selectedOption) {
setInputValue(selectedOption);
}
}, [selectedOption]);

const handleInputDropdownChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
setInputValue(value);

const filtered = Options.filter((item) =>
item.label.toLowerCase().includes(value.toLowerCase())
);
setFilteredItems(filtered);
};

const handleSelect = (item: DropdownItem) => {
setInputValue(item.label);
setIsDropdownOpen(false);
if (item.onClick) {
item.onClick();
}
};

const onFirstItemClick = () => {
setTextBoxInput(true);
setInputValue('');
setIsDropdownOpen(false);
};

const handleClose = () => {
setTextBoxInput(false);
setInputValue('');
setIsDropdownOpen(true);
};
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>)=>{
setNewInput(e.target.value);
setInputValue(e.target.value);
}
return (
<div ref={dropdownRef} className="input-dropdown">
{textBoxInput ? (
<InputGroup>
<FormInput
value={inputValue}
onChange={handleInputChange}
ariaLabel={ariaLabelforInput}
dataTestid={dataTestIdforInput}
isInvalid={isInvalid}
icon={<CloseIcon onClick={handleClose} color='#253DF4' data-testid="close-input" aria-label="Close input "/>}
className="input-with-close"
label={dropdownLabel}
feedback={feedback}
/>
</InputGroup>
) : (
<InputGroup>
<FormInput
placeholder={placeholder}
value={inputValue}
onChange={handleInputDropdownChange}
onClick={toggleDropdown}
ariaLabel={ariaLabelforDropdown}
dataTestid={dataTestIdforDropdown}
icon={<ChevronIcon data-testid="dropdown-input" aria-label="dropdown input"/>}
className={`${isDropdownOpen ? 'border-input collapsed' : ''}`}
onIconClick={toggleDropdown}
label={dropdownLabel}
required={required}
/>
</InputGroup>
)}

{!textBoxInput && isDropdownOpen && (
<ListGroup>
{isAllowInput && (
<ListGroup.Item
onClick={onFirstItemClick}
className="list-first-item-btn"
data-testid="list-first-item"
>
{firstItemLabel}
</ListGroup.Item>
)}
{(filteredItems.length > 0 ? filteredItems : Options).map((item, index) => (
<ListGroup.Item
key={index}
onClick={() => handleSelect(item)}
data-testid={`list-${index}-item`}
aria-label={`list-${item.label}-item`}
>
{item.label}
</ListGroup.Item>
))}
</ListGroup>
)}
</div>
);
};


12 changes: 5 additions & 7 deletions forms-flow-components/src/components/CustomComponents/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { InputGroup, FormControl } from 'react-bootstrap';
import { CloseIcon } from "../SvgIcons/index";

interface CustomSearchProps {
searchFormLoading: boolean;
searchLoading: boolean;
handleClearSearch: () => void;
search: string;
setSearch: (value: string) => void;
Expand All @@ -14,7 +14,7 @@ interface CustomSearchProps {
}

export const CustomSearch: FC<CustomSearchProps> = ({
searchFormLoading,
searchLoading,
handleClearSearch,
search,
setSearch,
Expand All @@ -23,7 +23,7 @@ export const CustomSearch: FC<CustomSearchProps> = ({
title = "Search",
dataTestId
}) => {
const inputClassNames = `d-flex align-items-center search-box-input ${searchFormLoading ? 'is-searching' : search ? 'has-value' : ''
const inputClassNames = `d-flex align-items-center search-box-input ${searchLoading ? 'is-searching' : search ? 'has-value' : ''
}`;

return (
Expand All @@ -41,16 +41,14 @@ export const CustomSearch: FC<CustomSearchProps> = ({
/>
{search && (
<span
className={`d-flex search-box-icon ${searchFormLoading ? 'loading' : ''}`}
onClick={!searchFormLoading && handleClearSearch}
className={`d-flex search-box-icon ${searchLoading ? 'loading' : ''}`}
>
{!searchFormLoading ? (
{!searchLoading ? (
<CloseIcon
width={16}
height={16}
onClick={handleClearSearch}
data-testid="form-search-clear-button"

/>
) : (
<div className="search-spinner"></div>
Expand Down
Loading

0 comments on commit ad37cf9

Please sign in to comment.