Skip to content

Commit

Permalink
Merge branch 'dev' into bal-3096
Browse files Browse the repository at this point in the history
  • Loading branch information
Omri-Levy committed Dec 26, 2024
2 parents 1eb6352 + 3294577 commit fbc7b97
Show file tree
Hide file tree
Showing 49 changed files with 946 additions and 351 deletions.
9 changes: 9 additions & 0 deletions apps/backoffice-v2/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# @ballerine/backoffice-v2

## 0.7.83

### Patch Changes

- added command.loading
- Updated dependencies
- @ballerine/ui@0.5.53
- @ballerine/react-pdf-toolkit@1.2.53

## 0.7.82

### Patch Changes
Expand Down
6 changes: 3 additions & 3 deletions apps/backoffice-v2/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ballerine/backoffice-v2",
"version": "0.7.82",
"version": "0.7.83",
"description": "Ballerine - Backoffice",
"homepage": "https://github.com/ballerine-io/ballerine",
"type": "module",
Expand Down Expand Up @@ -53,8 +53,8 @@
"dependencies": {
"@ballerine/blocks": "0.2.30",
"@ballerine/common": "0.9.59",
"@ballerine/react-pdf-toolkit": "^1.2.51",
"@ballerine/ui": "^0.5.51",
"@ballerine/react-pdf-toolkit": "^1.2.53",
"@ballerine/ui": "^0.5.53",
"@ballerine/workflow-browser-sdk": "0.6.78",
"@ballerine/workflow-node-sdk": "0.6.78",
"@botpress/webchat": "^2.1.10",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ReactNode, useCallback, useState } from 'react';
import { CheckIcon, PlusCircledIcon } from '@radix-ui/react-icons';
import { ReactNode, useCallback } from 'react';
import {
Badge,
Button,
Expand All @@ -8,13 +9,14 @@ import {
CommandInput,
CommandItem,
CommandList,
CommandLoading,
CommandSeparator,
ctw,
Popover,
PopoverContent,
PopoverTrigger,
} from '@ballerine/ui';
import { CheckIcon, PlusCircledIcon } from '@radix-ui/react-icons';

import { Separator } from '@/common/components/atoms/Separator/Separator';

interface IMultiSelectProps<
Expand All @@ -25,10 +27,24 @@ interface IMultiSelectProps<
},
> {
title: string;
isLoading?: boolean;
selectedValues: Array<TOption['value']>;
onSelect: (value: Array<TOption['value']>) => void;
onClearSelect: () => void;
options: TOption[];
props?: {
content?: {
className?: string;
};
trigger?: {
leftIcon?: JSX.Element;
rightIcon?: JSX.Element;
className?: string;
title?: {
className?: string;
};
};
};
}

export const MultiSelect = <
Expand All @@ -39,32 +55,37 @@ export const MultiSelect = <
},
>({
title,
selectedValues,
isLoading,
selectedValues: selected,
onSelect,
onClearSelect,
options,
props,
}: IMultiSelectProps<TOption>) => {
const [selected, setSelected] = useState(selectedValues);

const onSelectChange = useCallback(
(value: TOption['value']) => {
const isSelected = selected.some(selectedValue => selectedValue === value);
const nextSelected = isSelected
? selected.filter(selectedValue => selectedValue !== value)
: [...selected, value];

setSelected(nextSelected);
onSelect(nextSelected);
},
[onSelect, selected],
);

const TriggerLeftIcon = props?.trigger?.leftIcon ?? <PlusCircledIcon className="mr-2 h-4 w-4" />;

return (
<Popover>
<PopoverTrigger asChild>
<Button variant="outline" size="sm" className="h-8 border">
<PlusCircledIcon className="mr-2 h-4 w-4" />
{title}
<Button
variant="outline"
size="sm"
className={ctw(`h-8 border`, props?.trigger?.className)}
>
{TriggerLeftIcon}
<span className={ctw(props?.trigger?.title?.className)}>{title}</span>
{selected?.length > 0 && (
<>
<Separator orientation="vertical" className="mx-2 h-4" />
Expand All @@ -81,9 +102,9 @@ export const MultiSelect = <
.filter(option => selected.some(value => value === option.value))
.map(option => (
<Badge
key={`${option.value}`}
variant="secondary"
key={option.value}
className="rounded-sm px-1 font-normal"
className="max-w-[20ch] truncate rounded-sm px-1 font-normal"
>
{option.label}
</Badge>
Expand All @@ -92,52 +113,63 @@ export const MultiSelect = <
</div>
</>
)}
{props?.trigger?.rightIcon}
</Button>
</PopoverTrigger>
<PopoverContent className="w-[200px] p-0" align="start">
<Command>
<PopoverContent className={ctw(`w-[200px] p-0`, props?.content?.className)} align="start">
<Command filter={(value, search) => (value.includes(search) ? 1 : 0)}>
<CommandInput placeholder={title} />
<CommandList>
<CommandEmpty>No results found.</CommandEmpty>
<CommandGroup>
{options.map(option => {
const isSelected = selected.some(value => value === option.value);
{isLoading && (
<CommandLoading className={`flex items-center justify-center pb-3 text-sm`}>
Loading...
</CommandLoading>
)}
{!isLoading && options.length === 0 && <CommandEmpty>No results found.</CommandEmpty>}
{!isLoading && options.length > 0 && (
<CommandGroup>
<div className={`max-h-[250px] overflow-y-auto`}>
{options.map(option => {
const isSelected = selected.some(value => value === option.value);

return (
<CommandItem key={option.value} onSelect={() => onSelectChange(option.value)}>
<div
className={ctw(
'mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary',
isSelected
? 'bg-primary text-primary-foreground'
: 'opacity-50 [&_svg]:invisible',
)}
>
<CheckIcon className={ctw('h-4 w-4')} />
</div>
{option.icon}
<span>{option.label}</span>
</CommandItem>
);
})}
</CommandGroup>
{selected?.length > 0 && (
<>
<CommandSeparator />
<CommandGroup>
<CommandItem
onSelect={() => {
onClearSelect();
setSelected([]);
}}
className="justify-center text-center"
>
Clear filters
</CommandItem>
</CommandGroup>
</>
return (
<CommandItem
value={option.label}
key={`${option.value}`}
className={`cursor-pointer`}
onSelect={() => onSelectChange(option.value)}
>
<div
className={ctw(
'mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary',
isSelected
? 'bg-primary text-primary-foreground'
: 'opacity-50 [&_svg]:invisible',
)}
>
<CheckIcon className={ctw('h-4 w-4')} />
</div>
{option.icon}
<span>{option.label}</span>
</CommandItem>
);
})}
</div>
</CommandGroup>
)}
</CommandList>
<CommandSeparator />
<CommandGroup>
<CommandItem
onSelect={onClearSelect}
className={ctw(
`cursor-pointer justify-center text-center`,
selected.length === 0 && 'pointer-events-none opacity-50',
)}
>
Clear filters
</CommandItem>
</CommandGroup>
</Command>
</PopoverContent>
</Popover>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,35 @@ import { Calendar } from '../../organisms/Calendar/Calendar';
type TDateRangePickerProps = {
onChange: NonNullable<ComponentProps<typeof Calendar>['onSelect']>;
value: NonNullable<ComponentProps<typeof Calendar>['selected']>;
placeholder?: string;
className?: ComponentProps<'div'>['className'];
};

export const DateRangePicker = ({ onChange, value, className }: TDateRangePickerProps) => {
export const DateRangePicker = ({
onChange,
value,
placeholder,
className,
}: TDateRangePickerProps) => {
return (
<div className={ctw('grid gap-2', className)}>
<Popover>
<PopoverTrigger asChild>
<Button
id="date"
variant={'outline'}
className={ctw('w-[300px] justify-start text-left font-normal', {
className={ctw('h-8 w-[250px] justify-start text-left font-normal', {
'text-muted-foreground': !value,
})}
>
<CalendarIcon className="size-4 mr-2" />
<CalendarIcon className="mr-2 d-4" />
{value?.from && value?.to && (
<>
{formatDate(value.from, 'LLL dd, y')} - {formatDate(value.to, 'LLL dd, y')}
</>
)}
{value?.from && !value?.to && formatDate(value.from, 'LLL dd, y')}
{!value?.from && !value?.to && <span>Pick a date</span>}
{!value?.from && !value?.to && <span>{placeholder ?? 'Pick a date'}</span>}
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align="start">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@ import { FunctionComponent } from 'react';

export const Search: FunctionComponent<{
value: string;
placeholder?: string;
onChange: (search: string) => void;
}> = ({ value, onChange }) => {
}> = ({ value, placeholder, onChange }) => {
return (
<div className="relative flex flex-col gap-1">
<div className="input-group flex h-[32px] items-center rounded-[44px] border border-[#E5E7EB] shadow-[0_4px_4px_0_rgba(174,174,174,0.0625)]">
<div className="input-group flex h-[32px] w-[250px] items-center rounded-[44px] border border-[#E5E7EB] shadow-[0_4px_4px_0_rgba(174,174,174,0.0625)]">
<div className={`btn btn-square btn-ghost pointer-events-none -ms-2`}>
<LucideSearch size={13} />
</div>
<input
type={'search'}
className="input input-xs -ml-3 h-[18px] w-full !border-0 pl-0 text-xs !outline-none !ring-0 placeholder:text-base-content"
placeholder={`Search`}
placeholder={placeholder ?? `Search`}
value={value}
onChange={e => onChange(e.target.value)}
/>
Expand Down
Loading

0 comments on commit fbc7b97

Please sign in to comment.