diff --git a/frontend/appflowy_web_app/src/application/services/js-services/index.ts b/frontend/appflowy_web_app/src/application/services/js-services/index.ts index 91fb1bf4e3..b8df216c22 100644 --- a/frontend/appflowy_web_app/src/application/services/js-services/index.ts +++ b/frontend/appflowy_web_app/src/application/services/js-services/index.ts @@ -212,7 +212,6 @@ export class AFClientService implements AFService { async getCurrentUser () { const data = await APIService.getCurrentUser(); - await APIService.getWorkspaces(); return data; } diff --git a/frontend/appflowy_web_app/src/components/_shared/emoji-picker/EmojiPicker.hooks.ts b/frontend/appflowy_web_app/src/components/_shared/emoji-picker/EmojiPicker.hooks.ts index 6c47eaac9e..0dbc727a95 100644 --- a/frontend/appflowy_web_app/src/components/_shared/emoji-picker/EmojiPicker.hooks.ts +++ b/frontend/appflowy_web_app/src/components/_shared/emoji-picker/EmojiPicker.hooks.ts @@ -1,3 +1,4 @@ +import { notify } from '@/components/_shared/notify'; import { loadEmojiData } from '@/utils/emoji'; import { EmojiMartData } from '@emoji-mart/data'; import { PopoverProps } from '@mui/material/Popover'; @@ -16,8 +17,10 @@ interface Emoji { native: string; } -export function useLoadEmojiData({ onEmojiSelect }: { onEmojiSelect: (emoji: string) => void }) { +export function useLoadEmojiData ({ onEmojiSelect }: { onEmojiSelect: (emoji: string) => void }) { const [searchValue, setSearchValue] = useState(''); + const [loading, setLoading] = useState(false); + const [isEmpty, setIsEmpty] = useState(false); const [emojiCategories, setEmojiCategories] = useState([]); const [skin, setSkin] = useState(() => { return Number(localStorage.getItem('emoji-mart.skin')) || 0; @@ -30,40 +33,52 @@ export function useLoadEmojiData({ onEmojiSelect }: { onEmojiSelect: (emoji: str const searchEmojiData = useCallback( async (searchVal?: string) => { - const emojiData = await loadEmojiData(); + setLoading(true); + setIsEmpty(false); + try { + const emojiData = await loadEmojiData(); + const { emojis, categories } = emojiData as EmojiMartData; - const { emojis, categories } = emojiData as EmojiMartData; + const filteredCategories = categories + .map((category) => { + const { id, emojis: categoryEmojis } = category; - const filteredCategories = categories - .map((category) => { - const { id, emojis: categoryEmojis } = category; + return { + id, + emojis: categoryEmojis + .filter((emojiId) => { + const emoji = emojis[emojiId]; - return { - id, - emojis: categoryEmojis - .filter((emojiId) => { - const emoji = emojis[emojiId]; + if (!searchVal) return true; + return filterSearchValue(emoji, searchVal); + }) + .map((emojiId) => { + const emoji = emojis[emojiId]; + const { name, skins } = emoji; - if (!searchVal) return true; - return filterSearchValue(emoji, searchVal); - }) - .map((emojiId) => { - const emoji = emojis[emojiId]; - const { name, skins } = emoji; + return { + id: emojiId, + name, + native: skins[skin] ? skins[skin].native : skins[0].native, + }; + }), + }; + }) + .filter((category) => category.emojis.length > 0); - return { - id: emojiId, - name, - native: skins[skin] ? skins[skin].native : skins[0].native, - }; - }), - }; - }) - .filter((category) => category.emojis.length > 0); + if (filteredCategories.length === 0) { + setIsEmpty(true); + } - setEmojiCategories(filteredCategories); + setEmojiCategories(filteredCategories); + } catch (_e) { + notify.error('Failed to load emoji data'); + setIsEmpty(true); + } + + setLoading(false); }, - [skin] + [skin], ); useEffect(() => { @@ -80,7 +95,7 @@ export function useLoadEmojiData({ onEmojiSelect }: { onEmojiSelect: (emoji: str async (native: string) => { onEmojiSelect(native); }, - [onEmojiSelect] + [onEmojiSelect], ); return { @@ -90,10 +105,12 @@ export function useLoadEmojiData({ onEmojiSelect }: { onEmojiSelect: (emoji: str onSelect, onSkinChange, skin, + loading, + isEmpty, }; } -export function useSelectSkinPopoverProps(): PopoverProps & { +export function useSelectSkinPopoverProps (): PopoverProps & { onOpen: (event: React.MouseEvent) => void; onClose: () => void; } { @@ -118,12 +135,12 @@ export function useSelectSkinPopoverProps(): PopoverProps & { }; } -function filterSearchValue( +function filterSearchValue ( emoji: { name: string; keywords?: string[]; }, - searchValue: string + searchValue: string, ) { const { name, keywords } = emoji; const searchValueLowerCase = searchValue.toLowerCase(); @@ -134,7 +151,7 @@ function filterSearchValue( ); } -export function getRowsWithCategories(emojiCategories: EmojiCategory[], rowSize: number) { +export function getRowsWithCategories (emojiCategories: EmojiCategory[], rowSize: number) { const rows: { id: string; type: 'category' | 'emojis'; @@ -157,4 +174,4 @@ export function getRowsWithCategories(emojiCategories: EmojiCategory[], rowSize: }); }); return rows; -} +} \ No newline at end of file diff --git a/frontend/appflowy_web_app/src/components/_shared/emoji-picker/EmojiPicker.tsx b/frontend/appflowy_web_app/src/components/_shared/emoji-picker/EmojiPicker.tsx index d5d15fa966..952a3a7b85 100644 --- a/frontend/appflowy_web_app/src/components/_shared/emoji-picker/EmojiPicker.tsx +++ b/frontend/appflowy_web_app/src/components/_shared/emoji-picker/EmojiPicker.tsx @@ -1,8 +1,10 @@ +import CircularProgress from '@mui/material/CircularProgress'; import React from 'react'; import { useLoadEmojiData } from './EmojiPicker.hooks'; import EmojiPickerHeader from './EmojiPickerHeader'; import EmojiPickerCategories from './EmojiPickerCategories'; +import emptyImageSrc from '@/assets/images/empty.png'; interface Props { onEmojiSelect: (emoji: string) => void; @@ -11,8 +13,9 @@ interface Props { hideRemove?: boolean; } -export function EmojiPicker({ defaultEmoji, onEscape, ...props }: Props) { - const { skin, onSkinChange, emojiCategories, setSearchValue, searchValue, onSelect } = useLoadEmojiData(props); +export function EmojiPicker ({ defaultEmoji, onEscape, ...props }: Props) { + const { skin, onSkinChange, emojiCategories, setSearchValue, searchValue, onSelect, loading, isEmpty } = + useLoadEmojiData(props); return (
@@ -24,14 +27,22 @@ export function EmojiPicker({ defaultEmoji, onEscape, ...props }: Props) { searchValue={searchValue} onSearchChange={setSearchValue} /> - + {loading ? ( +
+ +
+ ) : isEmpty ? ( + {'No + ) : ( + + )}
); } -export default EmojiPicker; +export default EmojiPicker; \ No newline at end of file diff --git a/frontend/appflowy_web_app/src/components/as-template/AsTemplate.tsx b/frontend/appflowy_web_app/src/components/as-template/AsTemplate.tsx index 32cd5664e3..7136f41f99 100644 --- a/frontend/appflowy_web_app/src/components/as-template/AsTemplate.tsx +++ b/frontend/appflowy_web_app/src/components/as-template/AsTemplate.tsx @@ -13,6 +13,8 @@ import { useTranslation } from 'react-i18next'; import { ReactComponent as CloseIcon } from '@/assets/close.svg'; import { ReactComponent as DeleteIcon } from '@/assets/trash.svg'; import './template.scss'; +import { slugify } from '@/components/as-template/utils'; +import { ReactComponent as WebsiteIcon } from '@/assets/website.svg'; function AsTemplate ({ viewName, @@ -56,9 +58,10 @@ function AsTemplate ({ await service?.updateTemplate(template.view_id, formData); } else { await service?.createTemplate(formData); - await loadTemplate(); + } + await loadTemplate(); handleBack(); } catch (error) { // eslint-disable-next-line @@ -108,6 +111,15 @@ function AsTemplate ({ > {t('button.cancel')} + {template && }
{template &&