@orbe-agro/client-core 5.6.235 → 5.6.236
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/@ecme/assets/styles/app.css +3 -0
- package/dist/@ecme/assets/styles/tailwind/index.css +3 -0
- package/dist/@ecme/components/template/Footer.js +1 -1
- package/dist/@ecme/components/template/Search.js +4 -1
- package/dist/@ecme/components/template/Search.js.map +1 -1
- package/dist/@ecme/index.js +0 -2
- package/dist/@ecme/index.js.map +1 -1
- package/dist/@ecme/views/dashboards/FavoritesLanding/FavoritesLanding.js +92 -0
- package/dist/@ecme/views/dashboards/FavoritesLanding/FavoritesLanding.js.map +1 -0
- package/dist/@ecme/views/dashboards/FavoritesLanding/index.js +5 -0
- package/dist/@ecme/views/dashboards/FavoritesLanding/index.js.map +1 -0
- package/dist/@ecme/views/dashboards/FavoritesLanding/types.js +2 -0
- package/dist/@ecme/views/dashboards/FavoritesLanding/types.js.map +1 -0
- package/dist/@ecme/views/dashboards/FavoritesLanding/utils.js +36 -0
- package/dist/@ecme/views/dashboards/FavoritesLanding/utils.js.map +1 -0
- package/dist/@ecme/views/dashboards/index.js +1 -4
- package/dist/@ecme/views/dashboards/index.js.map +1 -1
- package/dist/@ecme/views/index.js +0 -2
- package/dist/@ecme/views/index.js.map +1 -1
- package/dist/@types/@ecme/components/template/Search.d.ts +2 -0
- package/dist/@types/@ecme/components/template/Search.d.ts.map +1 -1
- package/dist/@types/@ecme/views/dashboards/FavoritesLanding/FavoritesLanding.d.ts +9 -0
- package/dist/@types/@ecme/views/dashboards/FavoritesLanding/FavoritesLanding.d.ts.map +1 -0
- package/dist/@types/@ecme/views/dashboards/FavoritesLanding/index.d.ts +3 -0
- package/dist/@types/@ecme/views/dashboards/FavoritesLanding/index.d.ts.map +1 -0
- package/dist/@types/@ecme/views/dashboards/FavoritesLanding/types.d.ts +17 -0
- package/dist/@types/@ecme/views/dashboards/FavoritesLanding/types.d.ts.map +1 -0
- package/dist/@types/@ecme/views/dashboards/FavoritesLanding/utils.d.ts +5 -0
- package/dist/@types/@ecme/views/dashboards/FavoritesLanding/utils.d.ts.map +1 -0
- package/dist/@types/@ecme/views/dashboards/index.d.ts +0 -1
- package/dist/@types/@ecme/views/dashboards/index.d.ts.map +1 -1
- package/dist/@types/@ecme/views/index.d.ts +0 -1
- package/dist/@types/@ecme/views/index.d.ts.map +1 -1
- package/dist/base/assets/styles/init.css +3 -0
- package/lib/@ecme/components/template/Search.tsx +4 -1
- package/lib/@ecme/views/dashboards/FavoritesLanding/FavoritesLanding.tsx +124 -0
- package/lib/@ecme/views/dashboards/FavoritesLanding/index.ts +3 -0
- package/lib/@ecme/views/dashboards/FavoritesLanding/types.ts +17 -0
- package/lib/@ecme/views/dashboards/FavoritesLanding/utils.ts +51 -0
- package/lib/@ecme/views/dashboards/index.ts +1 -3
- package/lib/@ecme/views/index.ts +1 -1
- package/package.json +1 -1
|
@@ -3,7 +3,7 @@ import Container from "../shared/Container.js";
|
|
|
3
3
|
import classNames from "../../utils/classNames.js";
|
|
4
4
|
import { APP_NAME } from "../../constants/app.constant.js";
|
|
5
5
|
import { PAGE_CONTAINER_GUTTER_X } from "../../constants/theme.constant.js";
|
|
6
|
-
const version = true ? "5.6.
|
|
6
|
+
const version = true ? "5.6.236" : "0.0.0";
|
|
7
7
|
const FooterContent = () => {
|
|
8
8
|
return /* @__PURE__ */ jsxs("div", { className: "flex w-full flex-auto items-center justify-between", children: [
|
|
9
9
|
/* @__PURE__ */ jsxs("span", { children: [
|
|
@@ -13,6 +13,7 @@ import { apiFindFavoritosByUsuario, apiDeleteFavoritoMenu, apiCreateFavoritoMenu
|
|
|
13
13
|
import debounce from "lodash/debounce";
|
|
14
14
|
import { useState, useEffect, useMemo, useRef } from "react";
|
|
15
15
|
import Highlighter from "react-highlight-words";
|
|
16
|
+
import { mutate } from "swr";
|
|
16
17
|
import { useTranslation } from "react-i18next";
|
|
17
18
|
import { HiChevronRight, HiStar, HiOutlineStar, HiOutlineSearch, HiOutlineTrash } from "react-icons/hi";
|
|
18
19
|
import { PiMagnifyingGlassDuotone } from "react-icons/pi";
|
|
@@ -193,6 +194,7 @@ const _Search = ({ className }) => {
|
|
|
193
194
|
const created = await apiCreateFavoritoMenu({ menuKey });
|
|
194
195
|
setFavorites((prev) => [...prev, created]);
|
|
195
196
|
setFavoritedKeys((prev) => new Set(prev).add(menuKey));
|
|
197
|
+
mutate(["/api/favoritos-menu/usuario", userId]);
|
|
196
198
|
}
|
|
197
199
|
} catch {
|
|
198
200
|
toast.push(
|
|
@@ -456,6 +458,7 @@ const _Search = ({ className }) => {
|
|
|
456
458
|
};
|
|
457
459
|
const Search = withHeaderItem(_Search);
|
|
458
460
|
export {
|
|
459
|
-
Search as default
|
|
461
|
+
Search as default,
|
|
462
|
+
filterNavigationByAuthority
|
|
460
463
|
};
|
|
461
464
|
//# sourceMappingURL=Search.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Search.js","sources":["../../../../lib/@ecme/components/template/Search.tsx"],"sourcesContent":["import { NavigationTree } from '@/@types/navigation'\nimport Button from '@/components/ui/Button'\nimport Dialog from '@/components/ui/Dialog'\nimport Notification from '@/components/ui/Notification'\nimport ScrollBar from '@/components/ui/ScrollBar'\nimport toast from '@/components/ui/toast'\nimport navigationConfig from '@/configs/navigation.config'\nimport { NAV_ITEM_TYPE_ITEM } from '@/constants/navigation.constant'\nimport { useSessionUser } from '@/store/authStore'\nimport classNames from '@/utils/classNames'\nimport withHeaderItem from '@/utils/hoc/withHeaderItem'\nimport { TFavoritoMenuResponse } from '@base/@types/api/response/dadosMestres/TFavoritoMenuResponse'\nimport {\n apiCreateFavoritoMenu,\n apiDeleteFavoritoMenu,\n apiFindFavoritosByUsuario,\n} from '@base/services/modules/DadosMestres/FavoritoMenu/FavoritoMenuService'\nimport debounce from 'lodash/debounce'\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport Highlighter from 'react-highlight-words'\nimport { useTranslation } from 'react-i18next'\nimport {\n HiChevronRight,\n HiOutlineSearch,\n HiOutlineStar,\n HiOutlineTrash,\n HiStar,\n} from 'react-icons/hi'\nimport { PiMagnifyingGlassDuotone } from 'react-icons/pi'\nimport { Link } from 'react-router-dom'\nimport { Spinner } from '../ui'\n\ntype SearchData = {\n key: string\n path: string\n title: string\n icon: string\n category: string\n categoryTitle: string\n breadcrumbs: string[]\n}\n\ntype SearchResult = {\n title: string\n data: SearchData[]\n}\n\nconst filterNavigationByAuthority = (\n navTree: NavigationTree[],\n userAuthority: string[],\n): NavigationTree[] => {\n return navTree.reduce((acc: NavigationTree[], nav) => {\n if (nav.excludeWhenHasPaths && nav.excludeWhenHasPaths.length > 0) {\n const shouldExclude = nav.excludeWhenHasPaths.some((path) =>\n userAuthority.includes(path),\n )\n\n if (shouldExclude) {\n return acc\n }\n }\n\n if (nav.subMenu && nav.subMenu.length > 0) {\n const filteredSubMenu = filterNavigationByAuthority(\n nav.subMenu,\n userAuthority,\n )\n\n if (filteredSubMenu.length > 0) {\n acc.push({ ...nav, subMenu: filteredSubMenu })\n }\n } else if (\n (nav.path && userAuthority.includes(nav.path)) ||\n !nav.path\n ) {\n acc.push(nav)\n }\n\n return acc\n }, [])\n}\n\nconst ListItem = (props: {\n icon: string\n label: string\n url: string\n isLast?: boolean\n keyWord: string\n breadcrumbs: string[]\n onNavigate: () => void\n menuKey: string\n isFavorited: boolean\n favToggling: boolean\n onToggleFavorite: (menuKey: string) => void\n}) => {\n const {\n icon,\n label,\n url = '',\n keyWord,\n onNavigate,\n breadcrumbs,\n menuKey,\n isFavorited,\n favToggling,\n onToggleFavorite,\n } = props\n\n const makeBreadcrumbs = (breadcrumbs: string[]) => {\n return breadcrumbs.join(' / ')\n }\n\n return (\n <div className=\"flex items-center gap-1 pr-4\">\n <Link to={url} onClick={onNavigate} className=\"flex-1\">\n <div\n className={classNames(\n 'flex items-center justify-between rounded-xl p-3 cursor-pointer user-select',\n 'hover:bg-gray-100 dark:hover:bg-gray-700',\n )}\n >\n <div className=\"w-72\">\n <div className=\"overflow-hidden text-gray-900 dark:text-gray-300\">\n <Highlighter\n autoEscape\n highlightClassName={classNames(\n 'text-primary',\n 'underline bg-transparent font-semibold dark:text-white',\n )}\n searchWords={[keyWord]}\n textToHighlight={makeBreadcrumbs(breadcrumbs)}\n />\n </div>\n </div>\n <HiChevronRight className=\"shrink-0 text-lg\" />\n </div>\n </Link>\n\n <button\n type=\"button\"\n className=\"flex-shrink-0 rounded-lg p-2 text-lg transition-colors hover:bg-gray-100 dark:hover:bg-gray-700\"\n disabled={favToggling}\n onClick={(e) => {\n e.preventDefault()\n e.stopPropagation()\n onToggleFavorite(menuKey)\n }}\n >\n {favToggling ? (\n <Spinner size={18} />\n ) : isFavorited ? (\n <HiStar className=\"text-yellow-500\" />\n ) : (\n <HiOutlineStar className=\"text-gray-400 hover:text-yellow-500\" />\n )}\n </button>\n </div>\n )\n}\n\ntype NavigationTreeFlat = NavigationTree & { parents: string[] }\n\ntype NavItemInfo = {\n key: string\n path: string\n title: string\n}\n\nconst flattenNavTree = (\n navTree: NavigationTree[],\n): Map<string, NavItemInfo> => {\n const map = new Map<string, NavItemInfo>()\n\n const walk = (items: NavigationTree[]) => {\n for (const item of items) {\n if (item.type === NAV_ITEM_TYPE_ITEM && item.path) {\n map.set(item.key, {\n key: item.key,\n path: item.path,\n title: item.title,\n })\n }\n if (item.subMenu && item.subMenu.length > 0) {\n walk(item.subMenu)\n }\n }\n }\n\n walk(navTree)\n return map\n}\n\nconst navItemMap = flattenNavTree(navigationConfig)\n\nconst _Search = ({ className }: { className?: string }) => {\n const [loading, setLoading] = useState(false)\n const [searchDialogOpen, setSearchDialogOpen] = useState(false)\n const [searchResult, setSearchResult] = useState<SearchResult[]>([])\n const [noResult, setNoResult] = useState(false)\n const userAuthority = useSessionUser((state) => state.user.authority)\n\n // -- Favorites state --\n const [favDialogOpen, setFavDialogOpen] = useState(false)\n const [favLoading, setFavLoading] = useState(false)\n const [favorites, setFavorites] = useState<TFavoritoMenuResponse[]>([])\n const [removingId, setRemovingId] = useState<number | null>(null)\n const [favoritedKeys, setFavoritedKeys] = useState<Set<string>>(new Set())\n const [togglingKeys, setTogglingKeys] = useState<Set<string>>(new Set())\n const userId = useSessionUser((state) => state.user.userId)\n\n const loadFavorites = async () => {\n if (!userId) return\n setFavLoading(true)\n try {\n const data = await apiFindFavoritosByUsuario(Number(userId))\n setFavorites(data)\n setFavoritedKeys(new Set(data.map((f) => f.menuKey)))\n } catch {\n toast.push(\n <Notification title=\"Erro\" type=\"danger\">\n Falha ao carregar favoritos.\n </Notification>,\n )\n setFavorites([])\n setFavoritedKeys(new Set())\n } finally {\n setFavLoading(false)\n }\n }\n\n const handleFavRemove = async (id: number) => {\n setRemovingId(id)\n try {\n await apiDeleteFavoritoMenu(id)\n setFavorites((prev) => prev.filter((f) => f.id !== id))\n setFavoritedKeys((prev) => {\n const next = new Set(prev)\n const removed = favorites.find((f) => f.id === id)\n if (removed) next.delete(removed.menuKey)\n return next\n })\n } catch {\n toast.push(\n <Notification title=\"Erro\" type=\"danger\">\n Falha ao remover favorito.\n </Notification>,\n )\n } finally {\n setRemovingId(null)\n }\n }\n\n const handleFavToggle = async (menuKey: string) => {\n if (!userId || togglingKeys.has(menuKey)) return\n setTogglingKeys((prev) => new Set(prev).add(menuKey))\n try {\n if (favoritedKeys.has(menuKey)) {\n const fav = favorites.find((f) => f.menuKey === menuKey)\n if (fav) {\n await apiDeleteFavoritoMenu(fav.id)\n setFavorites((prev) => prev.filter((f) => f.id !== fav.id))\n setFavoritedKeys((prev) => {\n const next = new Set(prev)\n next.delete(menuKey)\n return next\n })\n }\n } else {\n const created = await apiCreateFavoritoMenu({ menuKey })\n setFavorites((prev) => [...prev, created])\n setFavoritedKeys((prev) => new Set(prev).add(menuKey))\n }\n } catch {\n toast.push(\n <Notification title=\"Erro\" type=\"danger\">\n {favoritedKeys.has(menuKey)\n ? 'Falha ao remover favorito.'\n : 'Falha ao adicionar favorito.'}\n </Notification>,\n )\n } finally {\n setTogglingKeys((prev) => {\n const next = new Set(prev)\n next.delete(menuKey)\n return next\n })\n }\n }\n\n const handleFavOpen = () => {\n setFavDialogOpen(true)\n }\n\n const handleFavClose = () => {\n setFavDialogOpen(false)\n }\n\n useEffect(() => {\n if (favDialogOpen) {\n loadFavorites()\n }\n }, [favDialogOpen, userId])\n\n // Also load favorites when search opens (for star toggles in results)\n useEffect(() => {\n if (searchDialogOpen && userId) {\n loadFavorites()\n }\n }, [searchDialogOpen, userId])\n\n const enrichedFavorites = useMemo(() => {\n return favorites.map((fav) => ({\n ...fav,\n navInfo: navItemMap.get(fav.menuKey),\n }))\n }, [favorites])\n\n // -- end favorites state --\n\n const inputRef = useRef<HTMLInputElement>(null)\n\n const handleReset = () => {\n setNoResult(false)\n setSearchResult([])\n }\n\n const handleSearchOpen = () => {\n setSearchDialogOpen(true)\n }\n\n const handleSearchClose = () => {\n setSearchDialogOpen(false)\n handleReset()\n }\n\n const debounceFn = debounce(handleDebounceFn, 750)\n\n const { t } = useTranslation()\n\n const flatNavTree = useMemo(() => {\n const arr: NavigationTreeFlat[] = []\n const filteredNavigationTree = filterNavigationByAuthority(\n navigationConfig,\n userAuthority || [],\n )\n\n const makeflat = (item: NavigationTree, parents: string[]) => {\n if (Array.isArray(item.subMenu) && item.subMenu.length > 0) {\n item.subMenu.forEach((item) =>\n makeflat(item, [...parents, t(item.translateKey)]),\n )\n }\n arr.push({ ...item, parents })\n }\n\n filteredNavigationTree.forEach(function f(item) {\n makeflat(item, [t(item.translateKey)])\n })\n\n return arr\n }, [userAuthority, t])\n\n const filterNavigationTreeFlat = (\n text: string,\n tree: NavigationTreeFlat[],\n ): NavigationTreeFlat[] => {\n const results = tree.filter(\n (item) =>\n item.type === NAV_ITEM_TYPE_ITEM &&\n item.parents.join().toUpperCase().includes(text.toUpperCase()),\n )\n\n return results\n }\n\n function navTreeFlatToSearchResult(\n tree: NavigationTreeFlat[],\n ): SearchResult[] {\n const navTreeSearchResult: SearchResult = {\n title: t('base.layout.search.results.navTree'),\n data: [],\n }\n tree.forEach((item) => {\n navTreeSearchResult.data.push({\n category: item.path,\n categoryTitle: item.title,\n icon: item.icon,\n key: item.key,\n path: item.path,\n title: t(item.translateKey, item.title),\n breadcrumbs: item.parents,\n })\n })\n return [navTreeSearchResult]\n }\n\n async function handleDebounceFn(query: string) {\n if (!query) {\n setLoading(false)\n setSearchResult([])\n return\n }\n\n if (noResult) {\n setNoResult(false)\n }\n\n const res = await filterNavigationTreeFlat(query, flatNavTree)\n\n if (res) {\n if (res.length === 0) {\n setNoResult(true)\n setSearchResult([])\n } else {\n setSearchResult(navTreeFlatToSearchResult(res))\n }\n }\n\n setLoading(false)\n }\n\n const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {\n setLoading(true)\n debounceFn(e.target.value)\n }\n\n useEffect(() => {\n if (searchDialogOpen) {\n const timeout = setTimeout(() => inputRef.current?.focus(), 100)\n return () => {\n clearTimeout(timeout)\n }\n }\n }, [searchDialogOpen])\n\n const handleNavigate = () => {\n handleSearchClose()\n }\n\n return (\n <>\n <div className=\"flex items-center gap-1\">\n <div\n className={classNames(className, 'text-2xl')}\n onClick={handleSearchOpen}\n >\n <PiMagnifyingGlassDuotone />\n </div>\n <div\n className={classNames(className, 'text-2xl')}\n onClick={handleFavOpen}\n >\n <HiOutlineStar />\n </div>\n </div>\n {/* Search dialog */}\n <Dialog\n contentClassName=\"p-0\"\n isOpen={searchDialogOpen}\n closable={false}\n onRequestClose={handleSearchClose}\n >\n <div>\n <div className=\"flex items-center justify-between border-b border-gray-200 px-4 dark:border-gray-600\">\n <div className=\"flex items-center\">\n <HiOutlineSearch className=\"text-xl\" />\n <input\n ref={inputRef}\n className=\"block w-full bg-transparent p-4 text-base text-gray-900 outline-none ring-0 dark:text-gray-100\"\n placeholder={t(\n 'common.input.placeholder.search',\n )}\n onChange={handleSearch}\n />\n </div>\n <Button size=\"xs\" onClick={handleSearchClose}>\n Esc\n </Button>\n </div>\n <div className=\"px-5 py-6\">\n {loading ? (\n <div className=\"flex items-center justify-center\">\n <Spinner size={40} />\n </div>\n ) : (\n <ScrollBar className=\"max-h-[350px] overflow-y-auto\">\n {searchResult.map((result) => (\n <div key={result.title} className=\"mb-4\">\n <h6 className=\"mb-3\">{result.title}</h6>\n {result.data.map((data, index) => (\n <ListItem\n key={data.title + index}\n icon={data.icon}\n breadcrumbs={data.breadcrumbs}\n label={data.title}\n url={data.path}\n keyWord={\n inputRef.current?.value ||\n ''\n }\n onNavigate={handleNavigate}\n menuKey={data.key}\n isFavorited={favoritedKeys.has(\n data.key,\n )}\n favToggling={togglingKeys.has(\n data.key,\n )}\n onToggleFavorite={\n handleFavToggle\n }\n />\n ))}\n </div>\n ))}\n {searchResult.length === 0 && noResult && (\n <div className=\"my-10 text-center text-lg\">\n <span className=\"pr-1\">\n {t('common.status.noResultsFor')}\n </span>\n <span className=\"heading-text\">\n {`'`}\n {inputRef.current?.value}\n {`'`}\n </span>\n </div>\n )}\n </ScrollBar>\n )}\n </div>\n </div>\n </Dialog>\n {/* Favorites dialog */}\n <Dialog\n contentClassName=\"p-0\"\n isOpen={favDialogOpen}\n closable={false}\n onRequestClose={handleFavClose}\n >\n <div>\n <div className=\"flex items-center justify-between border-b border-gray-200 px-4 py-4 dark:border-gray-600\">\n <div className=\"flex items-center gap-2\">\n <HiStar className=\"text-xl text-yellow-500\" />\n <h6 className=\"text-base font-semibold text-gray-900 dark:text-gray-100\">\n Favoritos\n </h6>\n </div>\n <Button size=\"xs\" onClick={handleFavClose}>\n Esc\n </Button>\n </div>\n <div className=\"px-5 py-6\">\n {favLoading ? (\n <div className=\"flex items-center justify-center py-10\">\n <Spinner size={40} />\n </div>\n ) : (\n <ScrollBar className=\"max-h-[350px] overflow-y-auto\">\n {enrichedFavorites.length === 0 ? (\n <div className=\"my-10 text-center text-lg text-gray-500\">\n Nenhum favorito salvo.\n </div>\n ) : (\n <div className=\"flex flex-col gap-1\">\n {enrichedFavorites.map((fav) => (\n <div\n key={fav.id}\n className=\"flex items-center gap-1 pr-4\"\n >\n <Link\n to={\n fav.navInfo?.path || '#'\n }\n className=\"flex-1\"\n onClick={handleFavClose}\n >\n <div className=\"user-select flex cursor-pointer items-center justify-between rounded-xl p-3 hover:bg-gray-100 dark:hover:bg-gray-700\">\n <div className=\"w-72\">\n <div className=\"overflow-hidden text-gray-900 dark:text-gray-300\">\n {fav.navInfo\n ?.title ||\n fav.menuKey}\n </div>\n </div>\n <HiChevronRight className=\"h-6 w-6 shrink-0\" />\n </div>\n </Link>\n <button\n type=\"button\"\n className=\"flex-shrink-0 rounded-lg p-2 text-lg text-gray-400 transition-colors hover:bg-gray-100 hover:text-red-500 dark:hover:bg-gray-700\"\n disabled={\n removingId === fav.id\n }\n onClick={(e) => {\n e.stopPropagation()\n handleFavRemove(fav.id)\n }}\n >\n {removingId === fav.id ? (\n <Spinner size={18} />\n ) : (\n <HiOutlineTrash />\n )}\n </button>\n </div>\n ))}\n </div>\n )}\n </ScrollBar>\n )}\n </div>\n </div>\n </Dialog>\n </>\n )\n}\n\nconst Search = withHeaderItem(_Search)\n\nexport default Search\n"],"names":["breadcrumbs","item"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Search.js","sources":["../../../../lib/@ecme/components/template/Search.tsx"],"sourcesContent":["import { NavigationTree } from '@/@types/navigation'\nimport Button from '@/components/ui/Button'\nimport Dialog from '@/components/ui/Dialog'\nimport Notification from '@/components/ui/Notification'\nimport ScrollBar from '@/components/ui/ScrollBar'\nimport toast from '@/components/ui/toast'\nimport navigationConfig from '@/configs/navigation.config'\nimport { NAV_ITEM_TYPE_ITEM } from '@/constants/navigation.constant'\nimport { useSessionUser } from '@/store/authStore'\nimport classNames from '@/utils/classNames'\nimport withHeaderItem from '@/utils/hoc/withHeaderItem'\nimport { TFavoritoMenuResponse } from '@base/@types/api/response/dadosMestres/TFavoritoMenuResponse'\nimport {\n apiCreateFavoritoMenu,\n apiDeleteFavoritoMenu,\n apiFindFavoritosByUsuario,\n} from '@base/services/modules/DadosMestres/FavoritoMenu/FavoritoMenuService'\nimport debounce from 'lodash/debounce'\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport Highlighter from 'react-highlight-words'\nimport { mutate } from 'swr'\nimport { useTranslation } from 'react-i18next'\nimport {\n HiChevronRight,\n HiOutlineSearch,\n HiOutlineStar,\n HiOutlineTrash,\n HiStar,\n} from 'react-icons/hi'\nimport { PiMagnifyingGlassDuotone } from 'react-icons/pi'\nimport { Link } from 'react-router-dom'\nimport { Spinner } from '../ui'\n\ntype SearchData = {\n key: string\n path: string\n title: string\n icon: string\n category: string\n categoryTitle: string\n breadcrumbs: string[]\n}\n\ntype SearchResult = {\n title: string\n data: SearchData[]\n}\n\nexport const filterNavigationByAuthority = (\n navTree: NavigationTree[],\n userAuthority: string[],\n): NavigationTree[] => {\n return navTree.reduce((acc: NavigationTree[], nav) => {\n if (nav.excludeWhenHasPaths && nav.excludeWhenHasPaths.length > 0) {\n const shouldExclude = nav.excludeWhenHasPaths.some((path) =>\n userAuthority.includes(path),\n )\n\n if (shouldExclude) {\n return acc\n }\n }\n\n if (nav.subMenu && nav.subMenu.length > 0) {\n const filteredSubMenu = filterNavigationByAuthority(\n nav.subMenu,\n userAuthority,\n )\n\n if (filteredSubMenu.length > 0) {\n acc.push({ ...nav, subMenu: filteredSubMenu })\n }\n } else if (\n (nav.path && userAuthority.includes(nav.path)) ||\n !nav.path\n ) {\n acc.push(nav)\n }\n\n return acc\n }, [])\n}\n\nconst ListItem = (props: {\n icon: string\n label: string\n url: string\n isLast?: boolean\n keyWord: string\n breadcrumbs: string[]\n onNavigate: () => void\n menuKey: string\n isFavorited: boolean\n favToggling: boolean\n onToggleFavorite: (menuKey: string) => void\n}) => {\n const {\n icon,\n label,\n url = '',\n keyWord,\n onNavigate,\n breadcrumbs,\n menuKey,\n isFavorited,\n favToggling,\n onToggleFavorite,\n } = props\n\n const makeBreadcrumbs = (breadcrumbs: string[]) => {\n return breadcrumbs.join(' / ')\n }\n\n return (\n <div className=\"flex items-center gap-1 pr-4\">\n <Link to={url} onClick={onNavigate} className=\"flex-1\">\n <div\n className={classNames(\n 'flex items-center justify-between rounded-xl p-3 cursor-pointer user-select',\n 'hover:bg-gray-100 dark:hover:bg-gray-700',\n )}\n >\n <div className=\"w-72\">\n <div className=\"overflow-hidden text-gray-900 dark:text-gray-300\">\n <Highlighter\n autoEscape\n highlightClassName={classNames(\n 'text-primary',\n 'underline bg-transparent font-semibold dark:text-white',\n )}\n searchWords={[keyWord]}\n textToHighlight={makeBreadcrumbs(breadcrumbs)}\n />\n </div>\n </div>\n <HiChevronRight className=\"shrink-0 text-lg\" />\n </div>\n </Link>\n\n <button\n type=\"button\"\n className=\"flex-shrink-0 rounded-lg p-2 text-lg transition-colors hover:bg-gray-100 dark:hover:bg-gray-700\"\n disabled={favToggling}\n onClick={(e) => {\n e.preventDefault()\n e.stopPropagation()\n onToggleFavorite(menuKey)\n }}\n >\n {favToggling ? (\n <Spinner size={18} />\n ) : isFavorited ? (\n <HiStar className=\"text-yellow-500\" />\n ) : (\n <HiOutlineStar className=\"text-gray-400 hover:text-yellow-500\" />\n )}\n </button>\n </div>\n )\n}\n\ntype NavigationTreeFlat = NavigationTree & { parents: string[] }\n\ntype NavItemInfo = {\n key: string\n path: string\n title: string\n}\n\nconst flattenNavTree = (\n navTree: NavigationTree[],\n): Map<string, NavItemInfo> => {\n const map = new Map<string, NavItemInfo>()\n\n const walk = (items: NavigationTree[]) => {\n for (const item of items) {\n if (item.type === NAV_ITEM_TYPE_ITEM && item.path) {\n map.set(item.key, {\n key: item.key,\n path: item.path,\n title: item.title,\n })\n }\n if (item.subMenu && item.subMenu.length > 0) {\n walk(item.subMenu)\n }\n }\n }\n\n walk(navTree)\n return map\n}\n\nconst navItemMap = flattenNavTree(navigationConfig)\n\nconst _Search = ({ className }: { className?: string }) => {\n const [loading, setLoading] = useState(false)\n const [searchDialogOpen, setSearchDialogOpen] = useState(false)\n const [searchResult, setSearchResult] = useState<SearchResult[]>([])\n const [noResult, setNoResult] = useState(false)\n const userAuthority = useSessionUser((state) => state.user.authority)\n\n // -- Favorites state --\n const [favDialogOpen, setFavDialogOpen] = useState(false)\n const [favLoading, setFavLoading] = useState(false)\n const [favorites, setFavorites] = useState<TFavoritoMenuResponse[]>([])\n const [removingId, setRemovingId] = useState<number | null>(null)\n const [favoritedKeys, setFavoritedKeys] = useState<Set<string>>(new Set())\n const [togglingKeys, setTogglingKeys] = useState<Set<string>>(new Set())\n const userId = useSessionUser((state) => state.user.userId)\n\n const loadFavorites = async () => {\n if (!userId) return\n setFavLoading(true)\n try {\n const data = await apiFindFavoritosByUsuario(Number(userId))\n setFavorites(data)\n setFavoritedKeys(new Set(data.map((f) => f.menuKey)))\n } catch {\n toast.push(\n <Notification title=\"Erro\" type=\"danger\">\n Falha ao carregar favoritos.\n </Notification>,\n )\n setFavorites([])\n setFavoritedKeys(new Set())\n } finally {\n setFavLoading(false)\n }\n }\n\n const handleFavRemove = async (id: number) => {\n setRemovingId(id)\n try {\n await apiDeleteFavoritoMenu(id)\n setFavorites((prev) => prev.filter((f) => f.id !== id))\n setFavoritedKeys((prev) => {\n const next = new Set(prev)\n const removed = favorites.find((f) => f.id === id)\n if (removed) next.delete(removed.menuKey)\n return next\n })\n } catch {\n toast.push(\n <Notification title=\"Erro\" type=\"danger\">\n Falha ao remover favorito.\n </Notification>,\n )\n } finally {\n setRemovingId(null)\n }\n }\n\n const handleFavToggle = async (menuKey: string) => {\n if (!userId || togglingKeys.has(menuKey)) return\n setTogglingKeys((prev) => new Set(prev).add(menuKey))\n try {\n if (favoritedKeys.has(menuKey)) {\n const fav = favorites.find((f) => f.menuKey === menuKey)\n if (fav) {\n await apiDeleteFavoritoMenu(fav.id)\n setFavorites((prev) => prev.filter((f) => f.id !== fav.id))\n setFavoritedKeys((prev) => {\n const next = new Set(prev)\n next.delete(menuKey)\n return next\n })\n }\n } else {\n const created = await apiCreateFavoritoMenu({ menuKey })\n setFavorites((prev) => [...prev, created])\n setFavoritedKeys((prev) => new Set(prev).add(menuKey))\n // revalida o cache usado pelo FavoritesLanding com o novo item salvo\n mutate(['/api/favoritos-menu/usuario', userId])\n }\n } catch {\n toast.push(\n <Notification title=\"Erro\" type=\"danger\">\n {favoritedKeys.has(menuKey)\n ? 'Falha ao remover favorito.'\n : 'Falha ao adicionar favorito.'}\n </Notification>,\n )\n } finally {\n setTogglingKeys((prev) => {\n const next = new Set(prev)\n next.delete(menuKey)\n return next\n })\n }\n }\n\n const handleFavOpen = () => {\n setFavDialogOpen(true)\n }\n\n const handleFavClose = () => {\n setFavDialogOpen(false)\n }\n\n useEffect(() => {\n if (favDialogOpen) {\n loadFavorites()\n }\n }, [favDialogOpen, userId])\n\n // Also load favorites when search opens (for star toggles in results)\n useEffect(() => {\n if (searchDialogOpen && userId) {\n loadFavorites()\n }\n }, [searchDialogOpen, userId])\n\n const enrichedFavorites = useMemo(() => {\n return favorites.map((fav) => ({\n ...fav,\n navInfo: navItemMap.get(fav.menuKey),\n }))\n }, [favorites])\n\n // -- end favorites state --\n\n const inputRef = useRef<HTMLInputElement>(null)\n\n const handleReset = () => {\n setNoResult(false)\n setSearchResult([])\n }\n\n const handleSearchOpen = () => {\n setSearchDialogOpen(true)\n }\n\n const handleSearchClose = () => {\n setSearchDialogOpen(false)\n handleReset()\n }\n\n const debounceFn = debounce(handleDebounceFn, 750)\n\n const { t } = useTranslation()\n\n const flatNavTree = useMemo(() => {\n const arr: NavigationTreeFlat[] = []\n const filteredNavigationTree = filterNavigationByAuthority(\n navigationConfig,\n userAuthority || [],\n )\n\n const makeflat = (item: NavigationTree, parents: string[]) => {\n if (Array.isArray(item.subMenu) && item.subMenu.length > 0) {\n item.subMenu.forEach((item) =>\n makeflat(item, [...parents, t(item.translateKey)]),\n )\n }\n arr.push({ ...item, parents })\n }\n\n filteredNavigationTree.forEach(function f(item) {\n makeflat(item, [t(item.translateKey)])\n })\n\n return arr\n }, [userAuthority, t])\n\n const filterNavigationTreeFlat = (\n text: string,\n tree: NavigationTreeFlat[],\n ): NavigationTreeFlat[] => {\n const results = tree.filter(\n (item) =>\n item.type === NAV_ITEM_TYPE_ITEM &&\n item.parents.join().toUpperCase().includes(text.toUpperCase()),\n )\n\n return results\n }\n\n function navTreeFlatToSearchResult(\n tree: NavigationTreeFlat[],\n ): SearchResult[] {\n const navTreeSearchResult: SearchResult = {\n title: t('base.layout.search.results.navTree'),\n data: [],\n }\n tree.forEach((item) => {\n navTreeSearchResult.data.push({\n category: item.path,\n categoryTitle: item.title,\n icon: item.icon,\n key: item.key,\n path: item.path,\n title: t(item.translateKey, item.title),\n breadcrumbs: item.parents,\n })\n })\n return [navTreeSearchResult]\n }\n\n async function handleDebounceFn(query: string) {\n if (!query) {\n setLoading(false)\n setSearchResult([])\n return\n }\n\n if (noResult) {\n setNoResult(false)\n }\n\n const res = await filterNavigationTreeFlat(query, flatNavTree)\n\n if (res) {\n if (res.length === 0) {\n setNoResult(true)\n setSearchResult([])\n } else {\n setSearchResult(navTreeFlatToSearchResult(res))\n }\n }\n\n setLoading(false)\n }\n\n const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {\n setLoading(true)\n debounceFn(e.target.value)\n }\n\n useEffect(() => {\n if (searchDialogOpen) {\n const timeout = setTimeout(() => inputRef.current?.focus(), 100)\n return () => {\n clearTimeout(timeout)\n }\n }\n }, [searchDialogOpen])\n\n const handleNavigate = () => {\n handleSearchClose()\n }\n\n return (\n <>\n <div className=\"flex items-center gap-1\">\n <div\n className={classNames(className, 'text-2xl')}\n onClick={handleSearchOpen}\n >\n <PiMagnifyingGlassDuotone />\n </div>\n <div\n className={classNames(className, 'text-2xl')}\n onClick={handleFavOpen}\n >\n <HiOutlineStar />\n </div>\n </div>\n {/* Search dialog */}\n <Dialog\n contentClassName=\"p-0\"\n isOpen={searchDialogOpen}\n closable={false}\n onRequestClose={handleSearchClose}\n >\n <div>\n <div className=\"flex items-center justify-between border-b border-gray-200 px-4 dark:border-gray-600\">\n <div className=\"flex items-center\">\n <HiOutlineSearch className=\"text-xl\" />\n <input\n ref={inputRef}\n className=\"block w-full bg-transparent p-4 text-base text-gray-900 outline-none ring-0 dark:text-gray-100\"\n placeholder={t(\n 'common.input.placeholder.search',\n )}\n onChange={handleSearch}\n />\n </div>\n <Button size=\"xs\" onClick={handleSearchClose}>\n Esc\n </Button>\n </div>\n <div className=\"px-5 py-6\">\n {loading ? (\n <div className=\"flex items-center justify-center\">\n <Spinner size={40} />\n </div>\n ) : (\n <ScrollBar className=\"max-h-[350px] overflow-y-auto\">\n {searchResult.map((result) => (\n <div key={result.title} className=\"mb-4\">\n <h6 className=\"mb-3\">{result.title}</h6>\n {result.data.map((data, index) => (\n <ListItem\n key={data.title + index}\n icon={data.icon}\n breadcrumbs={data.breadcrumbs}\n label={data.title}\n url={data.path}\n keyWord={\n inputRef.current?.value ||\n ''\n }\n onNavigate={handleNavigate}\n menuKey={data.key}\n isFavorited={favoritedKeys.has(\n data.key,\n )}\n favToggling={togglingKeys.has(\n data.key,\n )}\n onToggleFavorite={\n handleFavToggle\n }\n />\n ))}\n </div>\n ))}\n {searchResult.length === 0 && noResult && (\n <div className=\"my-10 text-center text-lg\">\n <span className=\"pr-1\">\n {t('common.status.noResultsFor')}\n </span>\n <span className=\"heading-text\">\n {`'`}\n {inputRef.current?.value}\n {`'`}\n </span>\n </div>\n )}\n </ScrollBar>\n )}\n </div>\n </div>\n </Dialog>\n {/* Favorites dialog */}\n <Dialog\n contentClassName=\"p-0\"\n isOpen={favDialogOpen}\n closable={false}\n onRequestClose={handleFavClose}\n >\n <div>\n <div className=\"flex items-center justify-between border-b border-gray-200 px-4 py-4 dark:border-gray-600\">\n <div className=\"flex items-center gap-2\">\n <HiStar className=\"text-xl text-yellow-500\" />\n <h6 className=\"text-base font-semibold text-gray-900 dark:text-gray-100\">\n Favoritos\n </h6>\n </div>\n <Button size=\"xs\" onClick={handleFavClose}>\n Esc\n </Button>\n </div>\n <div className=\"px-5 py-6\">\n {favLoading ? (\n <div className=\"flex items-center justify-center py-10\">\n <Spinner size={40} />\n </div>\n ) : (\n <ScrollBar className=\"max-h-[350px] overflow-y-auto\">\n {enrichedFavorites.length === 0 ? (\n <div className=\"my-10 text-center text-lg text-gray-500\">\n Nenhum favorito salvo.\n </div>\n ) : (\n <div className=\"flex flex-col gap-1\">\n {enrichedFavorites.map((fav) => (\n <div\n key={fav.id}\n className=\"flex items-center gap-1 pr-4\"\n >\n <Link\n to={\n fav.navInfo?.path || '#'\n }\n className=\"flex-1\"\n onClick={handleFavClose}\n >\n <div className=\"user-select flex cursor-pointer items-center justify-between rounded-xl p-3 hover:bg-gray-100 dark:hover:bg-gray-700\">\n <div className=\"w-72\">\n <div className=\"overflow-hidden text-gray-900 dark:text-gray-300\">\n {fav.navInfo\n ?.title ||\n fav.menuKey}\n </div>\n </div>\n <HiChevronRight className=\"h-6 w-6 shrink-0\" />\n </div>\n </Link>\n <button\n type=\"button\"\n className=\"flex-shrink-0 rounded-lg p-2 text-lg text-gray-400 transition-colors hover:bg-gray-100 hover:text-red-500 dark:hover:bg-gray-700\"\n disabled={\n removingId === fav.id\n }\n onClick={(e) => {\n e.stopPropagation()\n handleFavRemove(fav.id)\n }}\n >\n {removingId === fav.id ? (\n <Spinner size={18} />\n ) : (\n <HiOutlineTrash />\n )}\n </button>\n </div>\n ))}\n </div>\n )}\n </ScrollBar>\n )}\n </div>\n </div>\n </Dialog>\n </>\n )\n}\n\nconst Search = withHeaderItem(_Search)\n\nexport default Search\n"],"names":["breadcrumbs","item"],"mappings":"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"}
|
package/dist/@ecme/index.js
CHANGED
|
@@ -162,7 +162,6 @@ import { componentStyles } from "./assets/styles/components/index.js";
|
|
|
162
162
|
import { conceptsPlaceholder } from "./views/concepts/index.js";
|
|
163
163
|
import { default as default108 } from "./utils/cookiesStorage.js";
|
|
164
164
|
import { countryList } from "./constants/countries.constant.js";
|
|
165
|
-
import { dashboardsPlaceholder } from "./views/dashboards/index.js";
|
|
166
165
|
import { dateLocales } from "./locales/locales.js";
|
|
167
166
|
import { docsStyles } from "./assets/styles/docs/index.js";
|
|
168
167
|
import { default as default109 } from "./utils/fileSizeUnit.js";
|
|
@@ -439,7 +438,6 @@ export {
|
|
|
439
438
|
conceptsPlaceholder,
|
|
440
439
|
default108 as cookiesStorage,
|
|
441
440
|
countryList,
|
|
442
|
-
dashboardsPlaceholder,
|
|
443
441
|
dateLocales,
|
|
444
442
|
docsStyles,
|
|
445
443
|
default109 as fileSizeUnit,
|
package/dist/@ecme/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
import { useNavigate } from "react-router-dom";
|
|
4
|
+
import { useTranslation } from "react-i18next";
|
|
5
|
+
import useSWR from "swr";
|
|
6
|
+
import "../../../components/ui/Card/index.js";
|
|
7
|
+
import "../../../components/ui/Button/index.js";
|
|
8
|
+
import Loading from "../../../components/shared/Loading.js";
|
|
9
|
+
import navigationConfig from "../../../configs/navigation.config/index.js";
|
|
10
|
+
import navigationIcon from "../../../configs/navigation-icon.config.js";
|
|
11
|
+
import { filterNavigationByAuthority } from "../../../components/template/Search.js";
|
|
12
|
+
import { useSessionUser } from "../../../store/authStore.js";
|
|
13
|
+
import { apiFindFavoritosByUsuario } from "../../../../base/services/modules/DadosMestres/FavoritoMenu/FavoritoMenuService.js";
|
|
14
|
+
import { PiStarDuotone } from "react-icons/pi";
|
|
15
|
+
import { buildFavoriteNavMap } from "./utils.js";
|
|
16
|
+
import Card from "../../../components/ui/Card/Card.js";
|
|
17
|
+
import Button from "../../../components/ui/Button/Button.js";
|
|
18
|
+
const FavoritesLandingBase = ({
|
|
19
|
+
title = "Meus favoritos",
|
|
20
|
+
emptyStateMessage = "Você ainda não adicionou nenhum favorito. Use a busca para marcar páginas com a estrela.",
|
|
21
|
+
className
|
|
22
|
+
}) => {
|
|
23
|
+
const { t } = useTranslation();
|
|
24
|
+
const navigate = useNavigate();
|
|
25
|
+
const userId = useSessionUser((state) => state.user.userId);
|
|
26
|
+
const userAuthority = useSessionUser((state) => state.user.authority);
|
|
27
|
+
const { data: favorites, isLoading } = useSWR(
|
|
28
|
+
userId ? ["/api/favoritos-menu/usuario", userId] : null,
|
|
29
|
+
() => apiFindFavoritosByUsuario(Number(userId)),
|
|
30
|
+
{ revalidateOnFocus: false }
|
|
31
|
+
);
|
|
32
|
+
const navMap = useMemo(() => {
|
|
33
|
+
const filteredNavigationTree = filterNavigationByAuthority(
|
|
34
|
+
navigationConfig,
|
|
35
|
+
userAuthority || []
|
|
36
|
+
);
|
|
37
|
+
return buildFavoriteNavMap(filteredNavigationTree);
|
|
38
|
+
}, [userAuthority]);
|
|
39
|
+
const favoriteGroups = useMemo(() => {
|
|
40
|
+
if (!favorites || favorites.length === 0) return [];
|
|
41
|
+
const sorted = [...favorites].sort((a, b) => a.ordem - b.ordem);
|
|
42
|
+
const groups = /* @__PURE__ */ new Map();
|
|
43
|
+
sorted.forEach((fav) => {
|
|
44
|
+
const navInfo = navMap.get(fav.menuKey);
|
|
45
|
+
if (!navInfo) return;
|
|
46
|
+
const group = groups.get(navInfo.moduleKey);
|
|
47
|
+
if (group) {
|
|
48
|
+
group.items.push(navInfo);
|
|
49
|
+
} else {
|
|
50
|
+
groups.set(navInfo.moduleKey, {
|
|
51
|
+
moduleKey: navInfo.moduleKey,
|
|
52
|
+
moduleTitle: t(
|
|
53
|
+
navInfo.moduleTranslateKey,
|
|
54
|
+
navInfo.moduleTitle
|
|
55
|
+
),
|
|
56
|
+
items: [navInfo]
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
return Array.from(groups.values());
|
|
61
|
+
}, [favorites, navMap, t]);
|
|
62
|
+
return /* @__PURE__ */ jsx(Loading, { loading: isLoading, children: /* @__PURE__ */ jsxs("div", { className, children: [
|
|
63
|
+
/* @__PURE__ */ jsx("h3", { className: "mb-4", children: title }),
|
|
64
|
+
favoriteGroups.length === 0 ? /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx("p", { className: "text-center text-gray-500", children: emptyStateMessage }) }) : /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-4", children: favoriteGroups.map((group) => /* @__PURE__ */ jsx(
|
|
65
|
+
Card,
|
|
66
|
+
{
|
|
67
|
+
header: { content: group.moduleTitle },
|
|
68
|
+
children: /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3", children: group.items.map((item) => /* @__PURE__ */ jsx(
|
|
69
|
+
Button,
|
|
70
|
+
{
|
|
71
|
+
block: true,
|
|
72
|
+
className: "!justify-start gap-2 text-left",
|
|
73
|
+
icon: navigationIcon[item.icon] ?? /* @__PURE__ */ jsx(PiStarDuotone, {}),
|
|
74
|
+
onClick: () => navigate(item.path),
|
|
75
|
+
children: t(item.translateKey, item.title)
|
|
76
|
+
},
|
|
77
|
+
item.key
|
|
78
|
+
)) })
|
|
79
|
+
},
|
|
80
|
+
group.moduleKey
|
|
81
|
+
)) })
|
|
82
|
+
] }) });
|
|
83
|
+
};
|
|
84
|
+
const FavoritesLanding = () => {
|
|
85
|
+
return /* @__PURE__ */ jsx(FavoritesLandingBase, {});
|
|
86
|
+
};
|
|
87
|
+
export {
|
|
88
|
+
FavoritesLanding,
|
|
89
|
+
FavoritesLandingBase,
|
|
90
|
+
FavoritesLanding as default
|
|
91
|
+
};
|
|
92
|
+
//# sourceMappingURL=FavoritesLanding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FavoritesLanding.js","sources":["../../../../../lib/@ecme/views/dashboards/FavoritesLanding/FavoritesLanding.tsx"],"sourcesContent":["import { useMemo } from 'react'\nimport { useNavigate } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport useSWR from 'swr'\nimport Card from '@/components/ui/Card'\nimport Button from '@/components/ui/Button'\nimport Loading from '@/components/shared/Loading'\nimport navigationConfig from '@/configs/navigation.config'\nimport navigationIcon from '@/configs/navigation-icon.config'\nimport { filterNavigationByAuthority } from '@/components/template/Search'\nimport { useSessionUser } from '@/store/authStore'\nimport { apiFindFavoritosByUsuario } from '@base/services/modules/DadosMestres/FavoritoMenu/FavoritoMenuService'\nimport { PiStarDuotone } from 'react-icons/pi'\nimport { buildFavoriteNavMap } from './utils'\nimport type { FavoriteGroup } from './types'\n\ntype FavoritesLandingProps = {\n title?: string\n emptyStateMessage?: string\n className?: string\n}\n\nexport const FavoritesLandingBase = ({\n title = 'Meus favoritos',\n emptyStateMessage = 'Você ainda não adicionou nenhum favorito. Use a busca para marcar páginas com a estrela.',\n className,\n}: FavoritesLandingProps) => {\n const { t } = useTranslation()\n const navigate = useNavigate()\n const userId = useSessionUser((state) => state.user.userId)\n const userAuthority = useSessionUser((state) => state.user.authority)\n\n const { data: favorites, isLoading } = useSWR(\n userId ? ['/api/favoritos-menu/usuario', userId] : null,\n () => apiFindFavoritosByUsuario(Number(userId)),\n { revalidateOnFocus: false },\n )\n\n const navMap = useMemo(() => {\n const filteredNavigationTree = filterNavigationByAuthority(\n navigationConfig,\n userAuthority || [],\n )\n return buildFavoriteNavMap(filteredNavigationTree)\n }, [userAuthority])\n\n const favoriteGroups = useMemo<FavoriteGroup[]>(() => {\n if (!favorites || favorites.length === 0) return []\n\n const sorted = [...favorites].sort((a, b) => a.ordem - b.ordem)\n const groups = new Map<string, FavoriteGroup>()\n\n sorted.forEach((fav) => {\n const navInfo = navMap.get(fav.menuKey)\n if (!navInfo) return\n\n const group = groups.get(navInfo.moduleKey)\n if (group) {\n group.items.push(navInfo)\n } else {\n groups.set(navInfo.moduleKey, {\n moduleKey: navInfo.moduleKey,\n moduleTitle: t(\n navInfo.moduleTranslateKey,\n navInfo.moduleTitle,\n ),\n items: [navInfo],\n })\n }\n })\n\n return Array.from(groups.values())\n }, [favorites, navMap, t])\n\n return (\n <Loading loading={isLoading}>\n <div className={className}>\n <h3 className=\"mb-4\">{title}</h3>\n {favoriteGroups.length === 0 ? (\n <Card>\n <p className=\"text-center text-gray-500\">\n {emptyStateMessage}\n </p>\n </Card>\n ) : (\n <div className=\"flex flex-col gap-4\">\n {favoriteGroups.map((group) => (\n <Card\n key={group.moduleKey}\n header={{ content: group.moduleTitle }}\n >\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3\">\n {group.items.map((item) => (\n <Button\n key={item.key}\n block\n className=\"!justify-start gap-2 text-left\"\n icon={\n navigationIcon[item.icon] ?? (\n <PiStarDuotone />\n )\n }\n onClick={() =>\n navigate(item.path)\n }\n >\n {t(item.translateKey, item.title)}\n </Button>\n ))}\n </div>\n </Card>\n ))}\n </div>\n )}\n </div>\n </Loading>\n )\n}\n\nexport const FavoritesLanding = () => {\n return <FavoritesLandingBase />\n}\n\nexport default FavoritesLanding"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAsBO,MAAM,uBAAuB,CAAC;AAAA,EACjC,QAAQ;AAAA,EACR,oBAAoB;AAAA,EACpB;AACJ,MAA6B;AACzB,QAAM,EAAE,EAAA,IAAM,eAAA;AACd,QAAM,WAAW,YAAA;AACjB,QAAM,SAAS,eAAe,CAAC,UAAU,MAAM,KAAK,MAAM;AAC1D,QAAM,gBAAgB,eAAe,CAAC,UAAU,MAAM,KAAK,SAAS;AAEpE,QAAM,EAAE,MAAM,WAAW,UAAA,IAAc;AAAA,IACnC,SAAS,CAAC,+BAA+B,MAAM,IAAI;AAAA,IACnD,MAAM,0BAA0B,OAAO,MAAM,CAAC;AAAA,IAC9C,EAAE,mBAAmB,MAAA;AAAA,EAAM;AAG/B,QAAM,SAAS,QAAQ,MAAM;AACzB,UAAM,yBAAyB;AAAA,MAC3B;AAAA,MACA,iBAAiB,CAAA;AAAA,IAAC;AAEtB,WAAO,oBAAoB,sBAAsB;AAAA,EACrD,GAAG,CAAC,aAAa,CAAC;AAElB,QAAM,iBAAiB,QAAyB,MAAM;AAClD,QAAI,CAAC,aAAa,UAAU,WAAW,UAAU,CAAA;AAEjD,UAAM,SAAS,CAAC,GAAG,SAAS,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAC9D,UAAM,6BAAa,IAAA;AAEnB,WAAO,QAAQ,CAAC,QAAQ;AACpB,YAAM,UAAU,OAAO,IAAI,IAAI,OAAO;AACtC,UAAI,CAAC,QAAS;AAEd,YAAM,QAAQ,OAAO,IAAI,QAAQ,SAAS;AAC1C,UAAI,OAAO;AACP,cAAM,MAAM,KAAK,OAAO;AAAA,MAC5B,OAAO;AACH,eAAO,IAAI,QAAQ,WAAW;AAAA,UAC1B,WAAW,QAAQ;AAAA,UACnB,aAAa;AAAA,YACT,QAAQ;AAAA,YACR,QAAQ;AAAA,UAAA;AAAA,UAEZ,OAAO,CAAC,OAAO;AAAA,QAAA,CAClB;AAAA,MACL;AAAA,IACJ,CAAC;AAED,WAAO,MAAM,KAAK,OAAO,OAAA,CAAQ;AAAA,EACrC,GAAG,CAAC,WAAW,QAAQ,CAAC,CAAC;AAEzB,6BACK,SAAA,EAAQ,SAAS,WACd,UAAA,qBAAC,SAAI,WACD,UAAA;AAAA,IAAA,oBAAC,MAAA,EAAG,WAAU,QAAQ,UAAA,OAAM;AAAA,IAC3B,eAAe,WAAW,wBACtB,MAAA,EACG,UAAA,oBAAC,OAAE,WAAU,6BACR,6BACL,GACJ,wBAEC,OAAA,EAAI,WAAU,uBACV,UAAA,eAAe,IAAI,CAAC,UACjB;AAAA,MAAC;AAAA,MAAA;AAAA,QAEG,QAAQ,EAAE,SAAS,MAAM,YAAA;AAAA,QAEzB,UAAA,oBAAC,SAAI,WAAU,wDACV,gBAAM,MAAM,IAAI,CAAC,SACd;AAAA,UAAC;AAAA,UAAA;AAAA,YAEG,OAAK;AAAA,YACL,WAAU;AAAA,YACV,MACI,eAAe,KAAK,IAAI,yBACnB,eAAA,EAAc;AAAA,YAGvB,SAAS,MACL,SAAS,KAAK,IAAI;AAAA,YAGrB,UAAA,EAAE,KAAK,cAAc,KAAK,KAAK;AAAA,UAAA;AAAA,UAZ3B,KAAK;AAAA,QAAA,CAcjB,EAAA,CACL;AAAA,MAAA;AAAA,MArBK,MAAM;AAAA,IAAA,CAuBlB,EAAA,CACL;AAAA,EAAA,EAAA,CAER,EAAA,CACJ;AAER;AAEO,MAAM,mBAAmB,MAAM;AAClC,6BAAQ,sBAAA,EAAqB;AACjC;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { NAV_ITEM_TYPE_ITEM } from "../../../constants/navigation.constant.js";
|
|
2
|
+
const buildFavoriteNavMap = (navTree) => {
|
|
3
|
+
const map = /* @__PURE__ */ new Map();
|
|
4
|
+
const walk = (items, moduleInfo) => {
|
|
5
|
+
items.forEach((item) => {
|
|
6
|
+
const currentModule = moduleInfo ?? {
|
|
7
|
+
key: item.key,
|
|
8
|
+
title: item.title,
|
|
9
|
+
translateKey: item.translateKey,
|
|
10
|
+
icon: item.icon
|
|
11
|
+
};
|
|
12
|
+
if (item.type === NAV_ITEM_TYPE_ITEM && item.path) {
|
|
13
|
+
map.set(item.key, {
|
|
14
|
+
key: item.key,
|
|
15
|
+
path: item.path,
|
|
16
|
+
title: item.title,
|
|
17
|
+
translateKey: item.translateKey,
|
|
18
|
+
icon: item.icon,
|
|
19
|
+
moduleKey: currentModule.key,
|
|
20
|
+
moduleTitle: currentModule.title,
|
|
21
|
+
moduleTranslateKey: currentModule.translateKey,
|
|
22
|
+
moduleIcon: currentModule.icon
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
if (item.subMenu && item.subMenu.length > 0) {
|
|
26
|
+
walk(item.subMenu, currentModule);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
walk(navTree, null);
|
|
31
|
+
return map;
|
|
32
|
+
};
|
|
33
|
+
export {
|
|
34
|
+
buildFavoriteNavMap
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../../../../../lib/@ecme/views/dashboards/FavoritesLanding/utils.ts"],"sourcesContent":["import type { NavigationTree } from '@/@types/navigation'\nimport { NAV_ITEM_TYPE_ITEM } from '@/constants/navigation.constant'\nimport type { FavoriteNavInfo } from './types'\n\n/** Maps every leaf nav item to its top-level ancestor (the \"module\") for grouping favorites. */\nexport const buildFavoriteNavMap = (\n navTree: NavigationTree[],\n): Map<string, FavoriteNavInfo> => {\n const map = new Map<string, FavoriteNavInfo>()\n\n const walk = (\n items: NavigationTree[],\n moduleInfo: {\n key: string\n title: string\n translateKey: string\n icon: string\n } | null,\n ) => {\n items.forEach((item) => {\n const currentModule = moduleInfo ?? {\n key: item.key,\n title: item.title,\n translateKey: item.translateKey,\n icon: item.icon,\n }\n\n if (item.type === NAV_ITEM_TYPE_ITEM && item.path) {\n map.set(item.key, {\n key: item.key,\n path: item.path,\n title: item.title,\n translateKey: item.translateKey,\n icon: item.icon,\n moduleKey: currentModule.key,\n moduleTitle: currentModule.title,\n moduleTranslateKey: currentModule.translateKey,\n moduleIcon: currentModule.icon,\n })\n }\n\n if (item.subMenu && item.subMenu.length > 0) {\n walk(item.subMenu, currentModule)\n }\n })\n }\n\n walk(navTree, null)\n\n return map\n}\n"],"names":[],"mappings":";AAKO,MAAM,sBAAsB,CAC/B,YAC+B;AAC/B,QAAM,0BAAU,IAAA;AAEhB,QAAM,OAAO,CACT,OACA,eAMC;AACD,UAAM,QAAQ,CAAC,SAAS;AACpB,YAAM,gBAAgB,cAAc;AAAA,QAChC,KAAK,KAAK;AAAA,QACV,OAAO,KAAK;AAAA,QACZ,cAAc,KAAK;AAAA,QACnB,MAAM,KAAK;AAAA,MAAA;AAGf,UAAI,KAAK,SAAS,sBAAsB,KAAK,MAAM;AAC/C,YAAI,IAAI,KAAK,KAAK;AAAA,UACd,KAAK,KAAK;AAAA,UACV,MAAM,KAAK;AAAA,UACX,OAAO,KAAK;AAAA,UACZ,cAAc,KAAK;AAAA,UACnB,MAAM,KAAK;AAAA,UACX,WAAW,cAAc;AAAA,UACzB,aAAa,cAAc;AAAA,UAC3B,oBAAoB,cAAc;AAAA,UAClC,YAAY,cAAc;AAAA,QAAA,CAC7B;AAAA,MACL;AAEA,UAAI,KAAK,WAAW,KAAK,QAAQ,SAAS,GAAG;AACzC,aAAK,KAAK,SAAS,aAAa;AAAA,MACpC;AAAA,IACJ,CAAC;AAAA,EACL;AAEA,OAAK,SAAS,IAAI;AAElB,SAAO;AACX;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
@@ -2,7 +2,6 @@ import { default as default2 } from "./Views.js";
|
|
|
2
2
|
import { authPlaceholder } from "./auth/index.js";
|
|
3
3
|
import { authDemoPlaceholder } from "./auth-demo/index.js";
|
|
4
4
|
import { conceptsPlaceholder } from "./concepts/index.js";
|
|
5
|
-
import { dashboardsPlaceholder } from "./dashboards/index.js";
|
|
6
5
|
import { guidePlaceholder } from "./guide/index.js";
|
|
7
6
|
import { uiComponentsPlaceholder } from "./ui-components/index.js";
|
|
8
7
|
import { othersPlaceholder } from "./others/index.js";
|
|
@@ -11,7 +10,6 @@ export {
|
|
|
11
10
|
authDemoPlaceholder,
|
|
12
11
|
authPlaceholder,
|
|
13
12
|
conceptsPlaceholder,
|
|
14
|
-
dashboardsPlaceholder,
|
|
15
13
|
guidePlaceholder,
|
|
16
14
|
othersPlaceholder,
|
|
17
15
|
uiComponentsPlaceholder
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { NavigationTree } from '@/@types/navigation';
|
|
2
|
+
export declare const filterNavigationByAuthority: (navTree: NavigationTree[], userAuthority: string[]) => NavigationTree[];
|
|
1
3
|
declare const Search: import("react").FC<import("@/utils/hoc/withHeaderItem").WithHeaderItemProps>;
|
|
2
4
|
export default Search;
|
|
3
5
|
//# sourceMappingURL=Search.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Search.d.ts","sourceRoot":"","sources":["../../../../../lib/@ecme/components/template/Search.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Search.d.ts","sourceRoot":"","sources":["../../../../../lib/@ecme/components/template/Search.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAgDpD,eAAO,MAAM,2BAA2B,GACpC,SAAS,cAAc,EAAE,EACzB,eAAe,MAAM,EAAE,KACxB,cAAc,EA8BhB,CAAA;AA2hBD,QAAA,MAAM,MAAM,8EAA0B,CAAA;AAEtC,eAAe,MAAM,CAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type FavoritesLandingProps = {
|
|
2
|
+
title?: string;
|
|
3
|
+
emptyStateMessage?: string;
|
|
4
|
+
className?: string;
|
|
5
|
+
};
|
|
6
|
+
export declare const FavoritesLandingBase: ({ title, emptyStateMessage, className, }: FavoritesLandingProps) => import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export declare const FavoritesLanding: () => import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export default FavoritesLanding;
|
|
9
|
+
//# sourceMappingURL=FavoritesLanding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FavoritesLanding.d.ts","sourceRoot":"","sources":["../../../../../../lib/@ecme/views/dashboards/FavoritesLanding/FavoritesLanding.tsx"],"names":[],"mappings":"AAgBA,KAAK,qBAAqB,GAAG;IACzB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,eAAO,MAAM,oBAAoB,GAAI,0CAIlC,qBAAqB,4CA2FvB,CAAA;AAED,eAAO,MAAM,gBAAgB,+CAE5B,CAAA;AAED,eAAe,gBAAgB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../lib/@ecme/views/dashboards/FavoritesLanding/index.ts"],"names":[],"mappings":"AAAA,OAAO,gBAAgB,MAAM,oBAAoB,CAAA;AAEjD,eAAe,gBAAgB,CAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type FavoriteNavInfo = {
|
|
2
|
+
key: string;
|
|
3
|
+
path: string;
|
|
4
|
+
title: string;
|
|
5
|
+
translateKey: string;
|
|
6
|
+
icon: string;
|
|
7
|
+
moduleKey: string;
|
|
8
|
+
moduleTitle: string;
|
|
9
|
+
moduleTranslateKey: string;
|
|
10
|
+
moduleIcon: string;
|
|
11
|
+
};
|
|
12
|
+
export type FavoriteGroup = {
|
|
13
|
+
moduleKey: string;
|
|
14
|
+
moduleTitle: string;
|
|
15
|
+
items: FavoriteNavInfo[];
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../../lib/@ecme/views/dashboards/FavoritesLanding/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG;IAC1B,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,EAAE,MAAM,CAAA;IACpB,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,UAAU,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IACxB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,eAAe,EAAE,CAAA;CAC3B,CAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { NavigationTree } from '@/@types/navigation';
|
|
2
|
+
import type { FavoriteNavInfo } from './types';
|
|
3
|
+
/** Maps every leaf nav item to its top-level ancestor (the "module") for grouping favorites. */
|
|
4
|
+
export declare const buildFavoriteNavMap: (navTree: NavigationTree[]) => Map<string, FavoriteNavInfo>;
|
|
5
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../../../lib/@ecme/views/dashboards/FavoritesLanding/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAEzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAE9C,gGAAgG;AAChG,eAAO,MAAM,mBAAmB,GAC5B,SAAS,cAAc,EAAE,KAC1B,GAAG,CAAC,MAAM,EAAE,eAAe,CA2C7B,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../lib/@ecme/views/dashboards/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../lib/@ecme/views/dashboards/index.ts"],"names":[],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../lib/@ecme/views/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,SAAS,CAAC;AAG3C,cAAc,QAAQ,CAAC;AAGvB,cAAc,aAAa,CAAC;AAG5B,cAAc,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../lib/@ecme/views/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,SAAS,CAAC;AAG3C,cAAc,QAAQ,CAAC;AAGvB,cAAc,aAAa,CAAC;AAG5B,cAAc,YAAY,CAAC;AAM3B,cAAc,SAAS,CAAC;AAGxB,cAAc,iBAAiB,CAAC;AAGhC,cAAc,UAAU,CAAC"}
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
import debounce from 'lodash/debounce'
|
|
19
19
|
import { useEffect, useMemo, useRef, useState } from 'react'
|
|
20
20
|
import Highlighter from 'react-highlight-words'
|
|
21
|
+
import { mutate } from 'swr'
|
|
21
22
|
import { useTranslation } from 'react-i18next'
|
|
22
23
|
import {
|
|
23
24
|
HiChevronRight,
|
|
@@ -45,7 +46,7 @@ type SearchResult = {
|
|
|
45
46
|
data: SearchData[]
|
|
46
47
|
}
|
|
47
48
|
|
|
48
|
-
const filterNavigationByAuthority = (
|
|
49
|
+
export const filterNavigationByAuthority = (
|
|
49
50
|
navTree: NavigationTree[],
|
|
50
51
|
userAuthority: string[],
|
|
51
52
|
): NavigationTree[] => {
|
|
@@ -269,6 +270,8 @@ const _Search = ({ className }: { className?: string }) => {
|
|
|
269
270
|
const created = await apiCreateFavoritoMenu({ menuKey })
|
|
270
271
|
setFavorites((prev) => [...prev, created])
|
|
271
272
|
setFavoritedKeys((prev) => new Set(prev).add(menuKey))
|
|
273
|
+
// revalida o cache usado pelo FavoritesLanding com o novo item salvo
|
|
274
|
+
mutate(['/api/favoritos-menu/usuario', userId])
|
|
272
275
|
}
|
|
273
276
|
} catch {
|
|
274
277
|
toast.push(
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { useMemo } from 'react'
|
|
2
|
+
import { useNavigate } from 'react-router-dom'
|
|
3
|
+
import { useTranslation } from 'react-i18next'
|
|
4
|
+
import useSWR from 'swr'
|
|
5
|
+
import Card from '@/components/ui/Card'
|
|
6
|
+
import Button from '@/components/ui/Button'
|
|
7
|
+
import Loading from '@/components/shared/Loading'
|
|
8
|
+
import navigationConfig from '@/configs/navigation.config'
|
|
9
|
+
import navigationIcon from '@/configs/navigation-icon.config'
|
|
10
|
+
import { filterNavigationByAuthority } from '@/components/template/Search'
|
|
11
|
+
import { useSessionUser } from '@/store/authStore'
|
|
12
|
+
import { apiFindFavoritosByUsuario } from '@base/services/modules/DadosMestres/FavoritoMenu/FavoritoMenuService'
|
|
13
|
+
import { PiStarDuotone } from 'react-icons/pi'
|
|
14
|
+
import { buildFavoriteNavMap } from './utils'
|
|
15
|
+
import type { FavoriteGroup } from './types'
|
|
16
|
+
|
|
17
|
+
type FavoritesLandingProps = {
|
|
18
|
+
title?: string
|
|
19
|
+
emptyStateMessage?: string
|
|
20
|
+
className?: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const FavoritesLandingBase = ({
|
|
24
|
+
title = 'Meus favoritos',
|
|
25
|
+
emptyStateMessage = 'Você ainda não adicionou nenhum favorito. Use a busca para marcar páginas com a estrela.',
|
|
26
|
+
className,
|
|
27
|
+
}: FavoritesLandingProps) => {
|
|
28
|
+
const { t } = useTranslation()
|
|
29
|
+
const navigate = useNavigate()
|
|
30
|
+
const userId = useSessionUser((state) => state.user.userId)
|
|
31
|
+
const userAuthority = useSessionUser((state) => state.user.authority)
|
|
32
|
+
|
|
33
|
+
const { data: favorites, isLoading } = useSWR(
|
|
34
|
+
userId ? ['/api/favoritos-menu/usuario', userId] : null,
|
|
35
|
+
() => apiFindFavoritosByUsuario(Number(userId)),
|
|
36
|
+
{ revalidateOnFocus: false },
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
const navMap = useMemo(() => {
|
|
40
|
+
const filteredNavigationTree = filterNavigationByAuthority(
|
|
41
|
+
navigationConfig,
|
|
42
|
+
userAuthority || [],
|
|
43
|
+
)
|
|
44
|
+
return buildFavoriteNavMap(filteredNavigationTree)
|
|
45
|
+
}, [userAuthority])
|
|
46
|
+
|
|
47
|
+
const favoriteGroups = useMemo<FavoriteGroup[]>(() => {
|
|
48
|
+
if (!favorites || favorites.length === 0) return []
|
|
49
|
+
|
|
50
|
+
const sorted = [...favorites].sort((a, b) => a.ordem - b.ordem)
|
|
51
|
+
const groups = new Map<string, FavoriteGroup>()
|
|
52
|
+
|
|
53
|
+
sorted.forEach((fav) => {
|
|
54
|
+
const navInfo = navMap.get(fav.menuKey)
|
|
55
|
+
if (!navInfo) return
|
|
56
|
+
|
|
57
|
+
const group = groups.get(navInfo.moduleKey)
|
|
58
|
+
if (group) {
|
|
59
|
+
group.items.push(navInfo)
|
|
60
|
+
} else {
|
|
61
|
+
groups.set(navInfo.moduleKey, {
|
|
62
|
+
moduleKey: navInfo.moduleKey,
|
|
63
|
+
moduleTitle: t(
|
|
64
|
+
navInfo.moduleTranslateKey,
|
|
65
|
+
navInfo.moduleTitle,
|
|
66
|
+
),
|
|
67
|
+
items: [navInfo],
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
return Array.from(groups.values())
|
|
73
|
+
}, [favorites, navMap, t])
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<Loading loading={isLoading}>
|
|
77
|
+
<div className={className}>
|
|
78
|
+
<h3 className="mb-4">{title}</h3>
|
|
79
|
+
{favoriteGroups.length === 0 ? (
|
|
80
|
+
<Card>
|
|
81
|
+
<p className="text-center text-gray-500">
|
|
82
|
+
{emptyStateMessage}
|
|
83
|
+
</p>
|
|
84
|
+
</Card>
|
|
85
|
+
) : (
|
|
86
|
+
<div className="flex flex-col gap-4">
|
|
87
|
+
{favoriteGroups.map((group) => (
|
|
88
|
+
<Card
|
|
89
|
+
key={group.moduleKey}
|
|
90
|
+
header={{ content: group.moduleTitle }}
|
|
91
|
+
>
|
|
92
|
+
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3">
|
|
93
|
+
{group.items.map((item) => (
|
|
94
|
+
<Button
|
|
95
|
+
key={item.key}
|
|
96
|
+
block
|
|
97
|
+
className="!justify-start gap-2 text-left"
|
|
98
|
+
icon={
|
|
99
|
+
navigationIcon[item.icon] ?? (
|
|
100
|
+
<PiStarDuotone />
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
onClick={() =>
|
|
104
|
+
navigate(item.path)
|
|
105
|
+
}
|
|
106
|
+
>
|
|
107
|
+
{t(item.translateKey, item.title)}
|
|
108
|
+
</Button>
|
|
109
|
+
))}
|
|
110
|
+
</div>
|
|
111
|
+
</Card>
|
|
112
|
+
))}
|
|
113
|
+
</div>
|
|
114
|
+
)}
|
|
115
|
+
</div>
|
|
116
|
+
</Loading>
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export const FavoritesLanding = () => {
|
|
121
|
+
return <FavoritesLandingBase />
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export default FavoritesLanding
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type FavoriteNavInfo = {
|
|
2
|
+
key: string
|
|
3
|
+
path: string
|
|
4
|
+
title: string
|
|
5
|
+
translateKey: string
|
|
6
|
+
icon: string
|
|
7
|
+
moduleKey: string
|
|
8
|
+
moduleTitle: string
|
|
9
|
+
moduleTranslateKey: string
|
|
10
|
+
moduleIcon: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type FavoriteGroup = {
|
|
14
|
+
moduleKey: string
|
|
15
|
+
moduleTitle: string
|
|
16
|
+
items: FavoriteNavInfo[]
|
|
17
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { NavigationTree } from '@/@types/navigation'
|
|
2
|
+
import { NAV_ITEM_TYPE_ITEM } from '@/constants/navigation.constant'
|
|
3
|
+
import type { FavoriteNavInfo } from './types'
|
|
4
|
+
|
|
5
|
+
/** Maps every leaf nav item to its top-level ancestor (the "module") for grouping favorites. */
|
|
6
|
+
export const buildFavoriteNavMap = (
|
|
7
|
+
navTree: NavigationTree[],
|
|
8
|
+
): Map<string, FavoriteNavInfo> => {
|
|
9
|
+
const map = new Map<string, FavoriteNavInfo>()
|
|
10
|
+
|
|
11
|
+
const walk = (
|
|
12
|
+
items: NavigationTree[],
|
|
13
|
+
moduleInfo: {
|
|
14
|
+
key: string
|
|
15
|
+
title: string
|
|
16
|
+
translateKey: string
|
|
17
|
+
icon: string
|
|
18
|
+
} | null,
|
|
19
|
+
) => {
|
|
20
|
+
items.forEach((item) => {
|
|
21
|
+
const currentModule = moduleInfo ?? {
|
|
22
|
+
key: item.key,
|
|
23
|
+
title: item.title,
|
|
24
|
+
translateKey: item.translateKey,
|
|
25
|
+
icon: item.icon,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (item.type === NAV_ITEM_TYPE_ITEM && item.path) {
|
|
29
|
+
map.set(item.key, {
|
|
30
|
+
key: item.key,
|
|
31
|
+
path: item.path,
|
|
32
|
+
title: item.title,
|
|
33
|
+
translateKey: item.translateKey,
|
|
34
|
+
icon: item.icon,
|
|
35
|
+
moduleKey: currentModule.key,
|
|
36
|
+
moduleTitle: currentModule.title,
|
|
37
|
+
moduleTranslateKey: currentModule.translateKey,
|
|
38
|
+
moduleIcon: currentModule.icon,
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (item.subMenu && item.subMenu.length > 0) {
|
|
43
|
+
walk(item.subMenu, currentModule)
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
walk(navTree, null)
|
|
49
|
+
|
|
50
|
+
return map
|
|
51
|
+
}
|
package/lib/@ecme/views/index.ts
CHANGED
package/package.json
CHANGED