allow external attendees (#141)
* [#122] added external attendees * fixup! [#122] added external attendees * fixup! [#122] added external attendees * Update src/components/Attendees/AttendeeSearch.tsx --------- Co-authored-by: Camille Moussu <cmoussu@linagora.com> Co-authored-by: Benoit TELLIER <btellier@linagora.com>
This commit is contained in:
@@ -27,6 +27,7 @@ describe("PeopleSearch", () => {
|
|||||||
const onChange = jest.fn();
|
const onChange = jest.fn();
|
||||||
renderWithProviders(
|
renderWithProviders(
|
||||||
<PeopleSearch
|
<PeopleSearch
|
||||||
|
objectTypes={["user"]}
|
||||||
selectedUsers={selectedUsers}
|
selectedUsers={selectedUsers}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ export default function UserSearch({
|
|||||||
<>
|
<>
|
||||||
<PeopleSearch
|
<PeopleSearch
|
||||||
selectedUsers={selectedUsers}
|
selectedUsers={selectedUsers}
|
||||||
|
objectTypes={["user", "contact"]}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onChange={(event: any, value: User[]) => {
|
onChange={(event: any, value: User[]) => {
|
||||||
setAttendees(
|
setAttendees(
|
||||||
@@ -48,6 +49,7 @@ export default function UserSearch({
|
|||||||
);
|
);
|
||||||
setSelectedUsers(value);
|
setSelectedUsers(value);
|
||||||
}}
|
}}
|
||||||
|
freeSolo
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -32,24 +32,32 @@ export interface User {
|
|||||||
export function PeopleSearch({
|
export function PeopleSearch({
|
||||||
selectedUsers,
|
selectedUsers,
|
||||||
onChange,
|
onChange,
|
||||||
|
objectTypes,
|
||||||
disabled,
|
disabled,
|
||||||
|
freeSolo,
|
||||||
onToggleEventPreview,
|
onToggleEventPreview,
|
||||||
}: {
|
}: {
|
||||||
selectedUsers: User[];
|
selectedUsers: User[];
|
||||||
onChange: Function;
|
onChange: Function;
|
||||||
|
objectTypes: string[];
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
freeSolo?: boolean;
|
||||||
onToggleEventPreview?: Function;
|
onToggleEventPreview?: Function;
|
||||||
}) {
|
}) {
|
||||||
const [query, setQuery] = useState("");
|
const [query, setQuery] = useState("");
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [options, setOptions] = useState<User[]>([]);
|
const [options, setOptions] = useState<User[]>([]);
|
||||||
|
|
||||||
|
const isValidEmail = (email: string) =>
|
||||||
|
/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
|
||||||
|
const [error, setError] = useState<string | null>(null);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const delayDebounceFn = setTimeout(async () => {
|
const delayDebounceFn = setTimeout(async () => {
|
||||||
if (query) {
|
if (query) {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const res = await searchUsers(query, ["user"]);
|
const res = await searchUsers(query, objectTypes);
|
||||||
setOptions(res);
|
setOptions(res);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
@@ -60,20 +68,40 @@ export function PeopleSearch({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
|
freeSolo={freeSolo}
|
||||||
multiple
|
multiple
|
||||||
options={options}
|
options={options}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
filterOptions={(x) => x}
|
filterOptions={(x) => x}
|
||||||
fullWidth
|
fullWidth
|
||||||
getOptionLabel={(option) => option.displayName || option.email}
|
getOptionLabel={(option) => {
|
||||||
|
if (typeof option === "object") {
|
||||||
|
return option.displayName || option.email;
|
||||||
|
} else {
|
||||||
|
return option;
|
||||||
|
}
|
||||||
|
}}
|
||||||
filterSelectedOptions
|
filterSelectedOptions
|
||||||
value={selectedUsers}
|
value={selectedUsers}
|
||||||
onInputChange={(event, value) => setQuery(value)}
|
onInputChange={(event, value) => setQuery(value)}
|
||||||
onChange={(event, value) => onChange(event, value)}
|
onChange={(event, value) => {
|
||||||
|
const last = value[value.length - 1];
|
||||||
|
if (typeof last === "string" && !isValidEmail(last)) {
|
||||||
|
setError(`"${last}" is not a valid email address`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setError(null);
|
||||||
|
const mapped = value.map((v: any) =>
|
||||||
|
typeof v === "string" ? { email: v } : v
|
||||||
|
);
|
||||||
|
onChange(event, mapped);
|
||||||
|
}}
|
||||||
renderInput={(params) => (
|
renderInput={(params) => (
|
||||||
<TextField
|
<TextField
|
||||||
{...params}
|
{...params}
|
||||||
|
error={!!error}
|
||||||
|
helperText={error}
|
||||||
placeholder="Search user"
|
placeholder="Search user"
|
||||||
label="Search user"
|
label="Search user"
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
@@ -124,16 +152,26 @@ export function PeopleSearch({
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
renderValue={(value, getTagProps) =>
|
renderValue={(value, getTagProps) =>
|
||||||
value.map((option, index) => (
|
value.map((option, index) => {
|
||||||
<Chip
|
const isString = typeof option === "string";
|
||||||
{...getTagProps({ index })}
|
const label = isString ? option : option.displayName || option.email;
|
||||||
sx={{
|
const chipColor = isString
|
||||||
backgroundColor: option.color,
|
? theme.palette.grey[300]
|
||||||
color: theme.palette.getContrastText(option.color ?? "#ffffffff"),
|
: (option.color ?? theme.palette.grey[300]);
|
||||||
}}
|
const textColor = theme.palette.getContrastText(chipColor);
|
||||||
label={option.displayName}
|
|
||||||
/>
|
return (
|
||||||
))
|
<Chip
|
||||||
|
{...getTagProps({ index })}
|
||||||
|
key={label}
|
||||||
|
sx={{
|
||||||
|
backgroundColor: chipColor,
|
||||||
|
color: textColor,
|
||||||
|
}}
|
||||||
|
label={label}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -259,6 +259,7 @@ export default function CalendarSearch({
|
|||||||
<CardHeader title="Browse other calendars" sx={{ pb: 0 }} />
|
<CardHeader title="Browse other calendars" sx={{ pb: 0 }} />
|
||||||
<CardContent sx={{ flex: 1, overflow: "auto" }}>
|
<CardContent sx={{ flex: 1, overflow: "auto" }}>
|
||||||
<PeopleSearch
|
<PeopleSearch
|
||||||
|
objectTypes={["user"]}
|
||||||
selectedUsers={selectedUsers}
|
selectedUsers={selectedUsers}
|
||||||
onChange={async (event: any, value: User[]) => {
|
onChange={async (event: any, value: User[]) => {
|
||||||
setSelectedUsers(value);
|
setSelectedUsers(value);
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ export function TempCalendarsInput({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<PeopleSearch
|
<PeopleSearch
|
||||||
|
objectTypes={["user"]}
|
||||||
selectedUsers={tempUsers}
|
selectedUsers={tempUsers}
|
||||||
onChange={handleUserChange}
|
onChange={handleUserChange}
|
||||||
onToggleEventPreview={handleToggleEventPreview}
|
onToggleEventPreview={handleToggleEventPreview}
|
||||||
|
|||||||
Reference in New Issue
Block a user