Remove client-side isLoggedIn value
[ProtonMail-WebClient.git] / packages / pass / components / Item / Search / SearchBar.tsx
bloba7e8f285727f8ba21dc3fa5f6e7912379f1396cc
1 import { type FC, memo, useEffect, useMemo, useRef, useState } from 'react';
2 import { useSelector } from 'react-redux';
4 import { c } from 'ttag';
6 import { Button, Input } from '@proton/atoms';
7 import { Icon } from '@proton/components';
8 import { usePassCore } from '@proton/pass/components/Core/PassCoreProvider';
9 import { getItemTypeOptions } from '@proton/pass/components/Item/Filters/Type';
10 import { useNavigation } from '@proton/pass/components/Navigation/NavigationProvider';
11 import { useDebouncedValue } from '@proton/pass/hooks/useDebouncedValue';
12 import { useSearchShortcut } from '@proton/pass/hooks/useSearchShortcut';
13 import { selectShare } from '@proton/pass/store/selectors';
14 import type { MaybeNull, ShareType } from '@proton/pass/types';
15 import { TelemetryEventName } from '@proton/pass/types/data/telemetry';
16 import { isEmptyString } from '@proton/pass/utils/string/is-empty-string';
18 import './SearchBar.scss';
20 type Props = {
21     disabled?: boolean;
22     initial?: MaybeNull<string>;
23     trash?: boolean;
26 const SEARCH_DEBOUNCE_TIME = 75;
28 const SearchBarRaw: FC<Props> = ({ disabled, initial, trash }) => {
29     const { onTelemetry } = usePassCore();
30     const { filters, setFilters, matchTrash } = useNavigation();
32     const [search, setSearch] = useState<string>(initial ?? '');
33     const debouncedSearch = useDebouncedValue(search, SEARCH_DEBOUNCE_TIME);
35     const inputRef = useRef<HTMLInputElement>(null);
36     const { selectedShareId, type = '*' } = filters;
38     const vault = useSelector(selectShare<ShareType.Vault>(selectedShareId));
40     const placeholder = useMemo(() => {
41         const ITEM_TYPE_TO_LABEL_MAP = getItemTypeOptions();
42         const pluralItemType = ITEM_TYPE_TO_LABEL_MAP[type].label.toLowerCase();
43         const vaultName = matchTrash ? c('Label').t`Trash` : vault?.content.name.trim();
45         switch (type) {
46             case '*':
47                 return vault || matchTrash
48                     ? c('Placeholder').t`Search in ${vaultName}`
49                     : c('Placeholder').t`Search in all vaults`;
50             default: {
51                 // translator: ${pluralItemType} can be either "logins", "notes", "aliases", or "cards". Full sentence example: "Search notes in all vaults"
52                 return vault || matchTrash
53                     ? c('Placeholder').t`Search ${pluralItemType} in ${vaultName}`
54                     : c('Placeholder').t`Search ${pluralItemType} in all vaults`;
55             }
56         }
57     }, [vault, type, matchTrash]);
59     const handleClear = () => {
60         setSearch('');
61         setFilters({ search: '' });
62         inputRef.current?.focus();
63     };
65     const handleFocus = () => inputRef.current?.select();
67     const handleBlur = () => {
68         if (isEmptyString(search)) return;
69         void onTelemetry(TelemetryEventName.SearchTriggered, {}, {});
70     };
72     useEffect(handleFocus, []);
73     useEffect(() => setFilters({ search: debouncedSearch }), [debouncedSearch]);
74     useEffect(() => setSearch((value) => filters.search || value), [filters.search]);
75     useSearchShortcut(handleFocus);
77     return (
78         <Input
79             autoFocus
80             className="pass-searchbar"
81             inputClassName="text-rg"
82             disabled={disabled}
83             onBlur={handleBlur}
84             onFocus={handleFocus}
85             onValue={setSearch}
86             placeholder={`${trash ? c('Placeholder').t`Search in Trash` : placeholder}…`}
87             prefix={<Icon name="magnifier" />}
88             ref={inputRef}
89             suffix={
90                 search !== '' && (
91                     <Button
92                         shape="ghost"
93                         size="small"
94                         color="weak"
95                         icon
96                         pill
97                         onClick={handleClear}
98                         title={c('Action').t`Clear search`}
99                     >
100                         <Icon name="cross" />
101                     </Button>
102                 )
103             }
104             value={search}
105         />
106     );
109 export const SearchBar = memo(SearchBarRaw);