forked from cerc-io/snowballtools-base
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
efc5a45bac | ||
|
|
7b5ba1a5d0 | ||
|
|
b35f4033c5 | ||
|
|
306d3235b3 |
@@ -6,7 +6,7 @@ import { Input, InputProps } from './shared/Input';
|
||||
const SearchBar: React.ForwardRefRenderFunction<
|
||||
HTMLInputElement,
|
||||
InputProps & RefAttributes<HTMLInputElement>
|
||||
> = ({ value, onChange, placeholder = 'Search', ...props }) => {
|
||||
> = ({ value, onChange, placeholder = 'Search', ...props }, ref) => {
|
||||
return (
|
||||
<div className="relative flex w-full">
|
||||
<Input
|
||||
@@ -18,6 +18,7 @@ const SearchBar: React.ForwardRefRenderFunction<
|
||||
appearance="borderless"
|
||||
className="w-full lg:w-[459px]"
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { AddProjectMemberInput, Permission } from 'gql-client';
|
||||
|
||||
import { Typography } from '@snowballtools/material-tailwind-react-fork';
|
||||
|
||||
import { Button } from 'components/shared/Button';
|
||||
import { Modal } from 'components/shared/Modal';
|
||||
import { Input } from 'components/shared/Input';
|
||||
import { Checkbox } from 'components/shared/Checkbox';
|
||||
import { Select, SelectOption } from 'components/shared/Select';
|
||||
import { AddProjectMemberInput, Permission } from 'gql-client';
|
||||
|
||||
interface AddMemberDialogProp {
|
||||
open: boolean;
|
||||
@@ -17,18 +17,30 @@ interface AddMemberDialogProp {
|
||||
|
||||
interface formData {
|
||||
emailAddress: string;
|
||||
permissions: {
|
||||
view: boolean;
|
||||
edit: boolean;
|
||||
};
|
||||
canEdit: boolean;
|
||||
}
|
||||
|
||||
const permissionViewOptions: SelectOption = {
|
||||
value: Permission.View,
|
||||
label: Permission.View,
|
||||
};
|
||||
const permissionEditOptions: SelectOption = {
|
||||
value: Permission.Edit,
|
||||
label: Permission.Edit,
|
||||
};
|
||||
const permissionsDropdownOptions: SelectOption[] = [
|
||||
permissionViewOptions,
|
||||
permissionEditOptions,
|
||||
];
|
||||
|
||||
const AddMemberDialog = ({
|
||||
open,
|
||||
handleOpen,
|
||||
handleAddMember,
|
||||
}: AddMemberDialogProp) => {
|
||||
const {
|
||||
watch,
|
||||
setValue,
|
||||
handleSubmit,
|
||||
register,
|
||||
reset,
|
||||
@@ -36,10 +48,7 @@ const AddMemberDialog = ({
|
||||
} = useForm({
|
||||
defaultValues: {
|
||||
emailAddress: '',
|
||||
permissions: {
|
||||
view: true,
|
||||
edit: false,
|
||||
},
|
||||
canEdit: false,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -47,11 +56,7 @@ const AddMemberDialog = ({
|
||||
reset();
|
||||
handleOpen();
|
||||
|
||||
const permissions = Object.entries(data.permissions)
|
||||
.filter(([, value]) => value)
|
||||
.map(
|
||||
([key]) => key.charAt(0).toUpperCase() + key.slice(1),
|
||||
) as Permission[];
|
||||
const permissions = [data.canEdit ? Permission.Edit : Permission.View];
|
||||
|
||||
await handleAddMember({ email: data.emailAddress, permissions });
|
||||
}, []);
|
||||
@@ -72,19 +77,19 @@ const AddMemberDialog = ({
|
||||
required: 'email field cannot be empty',
|
||||
})}
|
||||
/>
|
||||
<Typography variant="small">Permissions</Typography>
|
||||
<Typography variant="small">
|
||||
You can change this later if required.
|
||||
</Typography>
|
||||
<Checkbox
|
||||
label={Permission.View}
|
||||
{...register(`permissions.view`)}
|
||||
color="blue"
|
||||
/>
|
||||
<Checkbox
|
||||
label={Permission.Edit}
|
||||
{...register(`permissions.edit`)}
|
||||
color="blue"
|
||||
<Select
|
||||
label="Permissions"
|
||||
description="You can change this later if required."
|
||||
options={permissionsDropdownOptions}
|
||||
value={
|
||||
watch('canEdit') ? permissionEditOptions : permissionViewOptions
|
||||
}
|
||||
onChange={(value) =>
|
||||
setValue(
|
||||
'canEdit',
|
||||
(value as SelectOption)!.value === Permission.Edit,
|
||||
)
|
||||
}
|
||||
/>
|
||||
</Modal.Body>
|
||||
<Modal.Footer>
|
||||
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
useMemo,
|
||||
ComponentPropsWithoutRef,
|
||||
} from 'react';
|
||||
import { FieldValues, UseFormRegister } from 'react-hook-form';
|
||||
|
||||
import { WarningIcon } from 'components/shared/CustomIcon';
|
||||
import { cloneIcon } from 'utils/cloneIcon';
|
||||
@@ -12,7 +11,7 @@ import { cn } from 'utils/classnames';
|
||||
|
||||
import { InputTheme, inputTheme } from './Input.theme';
|
||||
|
||||
export interface InputProps<T extends FieldValues = FieldValues>
|
||||
export interface InputProps
|
||||
extends InputTheme,
|
||||
Omit<ComponentPropsWithoutRef<'input'>, 'size'> {
|
||||
label?: string;
|
||||
@@ -20,9 +19,6 @@ export interface InputProps<T extends FieldValues = FieldValues>
|
||||
leftIcon?: ReactNode;
|
||||
rightIcon?: ReactNode;
|
||||
helperText?: string;
|
||||
|
||||
// react-hook-form optional register
|
||||
register?: ReturnType<UseFormRegister<T>>;
|
||||
}
|
||||
|
||||
const Input = forwardRef<HTMLInputElement, InputProps>(
|
||||
@@ -34,7 +30,6 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
|
||||
leftIcon,
|
||||
rightIcon,
|
||||
helperText,
|
||||
register,
|
||||
size,
|
||||
state,
|
||||
appearance,
|
||||
@@ -107,12 +102,11 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
|
||||
<div className={containerCls({ class: className })}>
|
||||
{leftIcon && renderLeftIcon}
|
||||
<input
|
||||
{...(register ? register : {})}
|
||||
className={cn(inputCls(), {
|
||||
'pl-10': leftIcon,
|
||||
})}
|
||||
{...props}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
{rightIcon && renderRightIcon}
|
||||
</div>
|
||||
|
||||
@@ -103,10 +103,12 @@ export const UserSelect = ({ options, value }: UserSelectProps) => {
|
||||
<div className={theme.container()}>
|
||||
{/* Input */}
|
||||
<div
|
||||
{...getToggleButtonProps({
|
||||
ref: inputWrapperRef,
|
||||
suppressRefError: true,
|
||||
})}
|
||||
{...getToggleButtonProps(
|
||||
{
|
||||
ref: inputWrapperRef,
|
||||
},
|
||||
{ suppressRefError: true },
|
||||
)}
|
||||
onClick={() => !dropdownOpen && openMenu()}
|
||||
className="cursor-pointer relative py-2 pl-2 pr-4 flex min-w-[200px] w-full items-center justify-between rounded-xl bg-surface-card shadow-sm"
|
||||
>
|
||||
|
||||
@@ -16,7 +16,7 @@ const FIRST_MEMBER_CARD = 0;
|
||||
|
||||
const CollaboratorsTabPanel = () => {
|
||||
const client = useGQLClient();
|
||||
const { toast } = useToast();
|
||||
const { toast, dismiss } = useToast();
|
||||
const { project } = useOutletContext<OutletContextType>();
|
||||
|
||||
const [addmemberDialogOpen, setAddMemberDialogOpen] = useState(false);
|
||||
@@ -39,14 +39,14 @@ const CollaboratorsTabPanel = () => {
|
||||
id: 'member_added',
|
||||
title: 'Member added to project',
|
||||
variant: 'success',
|
||||
onDismiss() {},
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
} else {
|
||||
toast({
|
||||
id: 'member_not_added',
|
||||
title: 'Invitation not sent',
|
||||
variant: 'error',
|
||||
onDismiss() {},
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
}
|
||||
},
|
||||
@@ -63,14 +63,14 @@ const CollaboratorsTabPanel = () => {
|
||||
id: 'member_removed',
|
||||
title: 'Member removed from project',
|
||||
variant: 'success',
|
||||
onDismiss() {},
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
} else {
|
||||
toast({
|
||||
id: 'member_not_removed',
|
||||
title: 'Not able to remove member',
|
||||
variant: 'error',
|
||||
onDismiss() {},
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -86,14 +86,14 @@ const CollaboratorsTabPanel = () => {
|
||||
id: 'member_permission_updated',
|
||||
title: 'Project member permission updated',
|
||||
variant: 'success',
|
||||
onDismiss() {},
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
} else {
|
||||
toast({
|
||||
id: 'member_permission_not_updated',
|
||||
title: 'Project member permission not updated',
|
||||
variant: 'error',
|
||||
onDismiss() {},
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user