ability to register a shared calendar (#118)
Co-authored-by: Camille Moussu <cmoussu@linagora.com>
This commit is contained in:
@@ -1,21 +1,7 @@
|
||||
import {
|
||||
Autocomplete,
|
||||
Avatar,
|
||||
CircularProgress,
|
||||
ListItem,
|
||||
ListItemAvatar,
|
||||
ListItemText,
|
||||
TextField,
|
||||
} from "@mui/material";
|
||||
import { useEffect, useState } from "react";
|
||||
import { searchUsers } from "../../features/User/userAPI";
|
||||
import { userAttendee } from "../../features/User/userDataTypes";
|
||||
|
||||
interface User {
|
||||
email: string;
|
||||
displayName: string;
|
||||
avatarUrl: string;
|
||||
}
|
||||
import { PeopleSearch, User } from "./PeopleSearch";
|
||||
|
||||
export default function UserSearch({
|
||||
attendees,
|
||||
@@ -26,77 +12,43 @@ export default function UserSearch({
|
||||
setAttendees: Function;
|
||||
disabled?: boolean;
|
||||
}) {
|
||||
const [query, setQuery] = useState("");
|
||||
const [options, setOptions] = useState<User[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const [selectedUsers, setSelectedUsers] = useState(
|
||||
attendees.map((a) => ({
|
||||
email: a.cal_address,
|
||||
displayName: a.cn ?? "",
|
||||
avatarUrl: "",
|
||||
openpaasId: "",
|
||||
}))
|
||||
);
|
||||
useEffect(() => {
|
||||
const delayDebounceFn = setTimeout(async () => {
|
||||
if (query) {
|
||||
setLoading(true);
|
||||
const res = await searchUsers(query);
|
||||
setOptions(res);
|
||||
setLoading(false);
|
||||
}
|
||||
}, 300);
|
||||
|
||||
return () => clearTimeout(delayDebounceFn);
|
||||
}, [query]);
|
||||
|
||||
setSelectedUsers(
|
||||
attendees.map((a) => ({
|
||||
email: a.cal_address,
|
||||
displayName: a.cn ?? "",
|
||||
avatarUrl: "",
|
||||
openpaasId: "",
|
||||
}))
|
||||
);
|
||||
}, [attendees]);
|
||||
return (
|
||||
<Autocomplete
|
||||
multiple
|
||||
options={options}
|
||||
disabled={disabled}
|
||||
loading={loading}
|
||||
filterOptions={(x) => x}
|
||||
fullWidth
|
||||
getOptionLabel={(option) => option.displayName || option.email}
|
||||
filterSelectedOptions
|
||||
onInputChange={(event, value) => setQuery(value)}
|
||||
onChange={(event, value) =>
|
||||
setAttendees(
|
||||
value.map((a) => ({
|
||||
cn: a.displayName,
|
||||
cal_address: a.email,
|
||||
partstat: "NEED_ACTION",
|
||||
rsvp: "FALSE",
|
||||
role: "CHAIR",
|
||||
cutype: "INDIVIDUAL",
|
||||
}))
|
||||
)
|
||||
}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
label="Search user"
|
||||
InputProps={{
|
||||
...params.InputProps,
|
||||
endAdornment: (
|
||||
<>
|
||||
{loading ? (
|
||||
<CircularProgress color="inherit" size={20} />
|
||||
) : null}
|
||||
{params.InputProps.endAdornment}
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
renderOption={(props, option) => {
|
||||
if (attendees.find((a) => a.cal_address === option.email)) return;
|
||||
return (
|
||||
<ListItem {...props} key={option.email} disableGutters>
|
||||
<ListItemAvatar>
|
||||
<Avatar src={option.avatarUrl} alt={option.displayName} />
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary={option.displayName}
|
||||
secondary={option.email}
|
||||
/>
|
||||
</ListItem>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<>
|
||||
<PeopleSearch
|
||||
selectedUsers={selectedUsers}
|
||||
disabled={disabled}
|
||||
onChange={(event: any, value: User[]) => {
|
||||
setAttendees(
|
||||
value.map((a: User) => ({
|
||||
cn: a.displayName,
|
||||
cal_address: a.email,
|
||||
partstat: "NEED_ACTION",
|
||||
rsvp: "FALSE",
|
||||
role: "CHAIR",
|
||||
cutype: "INDIVIDUAL",
|
||||
}))
|
||||
);
|
||||
setSelectedUsers(value);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
import Autocomplete from "@mui/material/Autocomplete";
|
||||
import Avatar from "@mui/material/Avatar";
|
||||
import Box from "@mui/material/Box";
|
||||
import Button from "@mui/material/Button";
|
||||
import Card from "@mui/material/Card";
|
||||
import CardActions from "@mui/material/CardActions";
|
||||
import CardContent from "@mui/material/CardContent";
|
||||
import CardHeader from "@mui/material/CardHeader";
|
||||
import CircularProgress from "@mui/material/CircularProgress";
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import ListItem from "@mui/material/ListItem";
|
||||
import ListItemAvatar from "@mui/material/ListItemAvatar";
|
||||
import ListItemText from "@mui/material/ListItemText";
|
||||
import Modal from "@mui/material/Modal";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { useState, useEffect } from "react";
|
||||
import { searchUsers } from "../../features/User/userAPI";
|
||||
|
||||
export interface User {
|
||||
email: string;
|
||||
displayName: string;
|
||||
avatarUrl: string;
|
||||
openpaasId: string;
|
||||
}
|
||||
|
||||
export function PeopleSearch({
|
||||
selectedUsers,
|
||||
onChange,
|
||||
disabled,
|
||||
}: {
|
||||
selectedUsers: User[];
|
||||
onChange: Function;
|
||||
disabled?: boolean;
|
||||
}) {
|
||||
const [query, setQuery] = useState("");
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [options, setOptions] = useState<User[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const delayDebounceFn = setTimeout(async () => {
|
||||
if (query) {
|
||||
setLoading(true);
|
||||
const res = await searchUsers(query, ["user"]);
|
||||
setOptions(res);
|
||||
setLoading(false);
|
||||
}
|
||||
}, 300);
|
||||
|
||||
return () => clearTimeout(delayDebounceFn);
|
||||
}, [query]);
|
||||
|
||||
return (
|
||||
<Autocomplete
|
||||
multiple
|
||||
options={options}
|
||||
disabled={disabled}
|
||||
loading={loading}
|
||||
filterOptions={(x) => x}
|
||||
fullWidth
|
||||
getOptionLabel={(option) => option.displayName || option.email}
|
||||
filterSelectedOptions
|
||||
value={selectedUsers}
|
||||
onInputChange={(event, value) => setQuery(value)}
|
||||
onChange={(event, value) => onChange(event, value)}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
label="Search user"
|
||||
slotProps={{
|
||||
input: {
|
||||
...params.InputProps,
|
||||
endAdornment: (
|
||||
<>
|
||||
{loading ? (
|
||||
<CircularProgress color="inherit" size={20} />
|
||||
) : null}
|
||||
{params.InputProps.endAdornment}
|
||||
</>
|
||||
),
|
||||
},
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
renderOption={(props, option) => {
|
||||
if (selectedUsers.find((u) => u.email === option.email)) return;
|
||||
return (
|
||||
<ListItem
|
||||
{...props}
|
||||
key={option.email + option.displayName}
|
||||
disableGutters
|
||||
>
|
||||
<ListItemAvatar>
|
||||
<Avatar src={option.avatarUrl} alt={option.displayName} />
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary={option.displayName}
|
||||
secondary={option.email}
|
||||
/>
|
||||
</ListItem>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user