Skip to content

Commit

Permalink
1034 implement create promotion page (#1050)
Browse files Browse the repository at this point in the history
  • Loading branch information
nguyenvanhadncntt authored Sep 19, 2024
1 parent cd8dd4e commit 589a7a6
Show file tree
Hide file tree
Showing 20 changed files with 942 additions and 68 deletions.
85 changes: 84 additions & 1 deletion backoffice/common/items/Input.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { HTMLInputTypeAttribute } from 'react';
import { Path, RegisterOptions, UseFormRegister, FieldValues } from 'react-hook-form';
import { FieldValues, Path, RegisterOptions, UseFormRegister } from 'react-hook-form';

type InputProps<T extends FieldValues> = {
labelText: string;
Expand All @@ -10,12 +10,30 @@ type InputProps<T extends FieldValues> = {
registerOptions?: RegisterOptions;
defaultValue?: number | string | string[];
disabled?: boolean;
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
};

type CheckProps<T extends FieldValues> = InputProps<T> & {
defaultChecked?: any;
};

type SelectProps<T extends FieldValues> = InputProps<T> & {
options: any[];
placeholder?: string;
defaultValue?: number | string | string[];
disabled?: boolean;
isMultiple?: boolean;
onChange?: (event: React.ChangeEvent<HTMLSelectElement>) => void;
};

type DateProps<T extends FieldValues> = InputProps<T> & {
minDate?: Date;
maxDate?: Date;
defaultValue?: string;
disabled?: boolean;
placeholder?: string;
};

export const Input = <T extends FieldValues>({
labelText,
field,
Expand Down Expand Up @@ -111,3 +129,68 @@ export const Switch = <T extends FieldValues>({
</div>
</div>
);

export const Select = <T extends FieldValues>({
labelText,
field,
register,
registerOptions,
error,
options,
defaultValue,
placeholder,
disabled,
isMultiple,
onChange,
}: SelectProps<T> & {
options: any[];
}) => (
<div className="mb-3">
<label className="form-label" htmlFor={field}>
{labelText} {registerOptions?.required && <span className="text-danger">*</span>}
</label>
<select
id={field}
className={`form-select ${error ? 'border-danger' : ''}`}
{...register(field, registerOptions)}
defaultValue={defaultValue}
disabled={disabled}
multiple={isMultiple}
onChange={onChange}
>
<option value="" selected={!defaultValue} disabled>
{placeholder}
</option>
{options.map((item) => (
<option key={item.value} value={item.value}>
{item.label}
</option>
))}
</select>
<p className="error-field mt-1">{error}</p>
</div>
);

export const DatePicker = <T extends FieldValues>({
labelText,
field,
register,
registerOptions = {},
error,
defaultValue,
}: DateProps<T>) => (
<div className="mb-3">
<label className="form-label" htmlFor={field}>
{labelText} {registerOptions?.required && <span className="text-danger">*</span>}
</label>
<input
id={field}
className={`form-control ${error ? 'border-danger' : ''}`}
{...register(field, registerOptions)}
defaultValue={defaultValue}
type="date"
placeholder="dd/mm/yyyy"
/>
<p className="error-field mt-1">{error}</p>
</div>
);
110 changes: 110 additions & 0 deletions backoffice/modules/promotion/components/MultipleAutoComplete.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { useState } from 'react';
import { RegisterOptions, UseFormRegister } from 'react-hook-form';

type props = {
labelText: string;
field: string;
register: UseFormRegister<any>;
registerOptions?: RegisterOptions;
// error: string,
defaultValue?: any;
options?: any[];
fetchOptions: (data: any) => any;
onSelect: (value: any) => void;
onRemoveElement: (value: any) => void;
optionSelectedIds: number[];
isSubmitting: boolean;
};

const MultipleAutoComplete = (props: props) => {
const [isFocusing, setIsFocusing] = useState(false);
const [optionSelecteds, setOptionSelecteds] = useState<any[]>([]);
const queryData = (query: string) => {
props.fetchOptions(query);
};

const handleFocus = (isFocusing: boolean) => {
setTimeout(() => {
if (!props.isSubmitting) {
setIsFocusing(isFocusing);
} else {
setIsFocusing(false);
}
}, 150);
};

const selectOption = (option: any) => {
setOptionSelecteds([...optionSelecteds, option]);
props.onSelect(option.id);
};

const removeOption = (option: any) => {
setOptionSelecteds(optionSelecteds.filter((item) => item.id !== option.id));
props.onRemoveElement(option.id);
};

return (
<div className="autocomplete-container">
<label className="form-label" htmlFor={props.field}>
{props.labelText}
</label>
<div>
<input
type="text"
id={props.field}
{...props.register(props.field, props.registerOptions)}
defaultValue={props.defaultValue}
onChange={(e) => queryData(e.target.value)}
onFocus={() => handleFocus(true)}
onBlur={() => handleFocus(false)}
className="form-control"
/>
{isFocusing && props.options!.length > 0 && (
<div className="autocomplete-list" style={{ maxHeight: '200px', overflowY: 'scroll' }}>
{props.options!.map((option, index) => (
<div
key={option.id}
aria-hidden="true"
className={`dropdown-item ${
props.optionSelectedIds.includes(option.id) ? 'selected-options' : ''
}`}
onClick={() => selectOption(option)}
>
{option.name}
</div>
))}
</div>
)}
</div>

{optionSelecteds.length > 0 && (
<div className="mt-3">
<span className="form-label">Selected {props.labelText}</span>
{optionSelecteds.map((option, index) => (
<div
className="d-flex align-items-center"
style={{
marginBottom: '5px',
borderRadius: '5px',
border: '1px solid #ccc',
padding: '5px',
}}
key={option.id}
>
<div className="mr-3" style={{ display: 'inline', marginRight: '15px' }}>
{option.name}
</div>
<span
aria-hidden="true"
className="fa fa-remove"
onClick={() => removeOption(option)}
></span>
</div>
))}
</div>
)}
</div>
);
};

export default MultipleAutoComplete;
Loading

0 comments on commit 589a7a6

Please sign in to comment.