diff --git a/api/v1/redirector.go b/api/v1/redirector.go index f9b568f..d5d8553 100644 --- a/api/v1/redirector.go +++ b/api/v1/redirector.go @@ -30,7 +30,7 @@ func (s *APIV1Service) registerRedirectorRoutes(g *echo.Group) { return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("failed to get shortcut, err: %s", err)).SetInternal(err) } if shortcut == nil { - return echo.NewHTTPError(http.StatusNotFound, fmt.Sprintf("not found shortcut with name: %s", shortcutName)) + return c.Redirect(http.StatusSeeOther, fmt.Sprintf("/404?shortcut=%s", shortcutName)) } if shortcut.Visibility != storepb.Visibility_PUBLIC { userID, ok := c.Get(userIDContextKey).(int32) diff --git a/frontend/web/src/components/CreateShortcutDialog.tsx b/frontend/web/src/components/CreateShortcutDialog.tsx index d553448..7e88f54 100644 --- a/frontend/web/src/components/CreateShortcutDialog.tsx +++ b/frontend/web/src/components/CreateShortcutDialog.tsx @@ -1,6 +1,6 @@ import { Button, Divider, Input, Modal, ModalDialog, Radio, RadioGroup, Textarea } from "@mui/joy"; import classnames from "classnames"; -import { isUndefined } from "lodash-es"; +import { isUndefined, uniq } from "lodash-es"; import { useEffect, useState } from "react"; import { toast } from "react-hot-toast"; import { useTranslation } from "react-i18next"; @@ -11,6 +11,7 @@ import Icon from "./Icon"; interface Props { shortcutId?: ShortcutId; + initialShortcut?: Partial; onClose: () => void; onConfirm?: () => void; } @@ -22,7 +23,7 @@ interface State { const visibilities: Visibility[] = ["PRIVATE", "WORKSPACE", "PUBLIC"]; const CreateShortcutDialog: React.FC = (props: Props) => { - const { onClose, onConfirm, shortcutId } = props; + const { onClose, onConfirm, shortcutId, initialShortcut } = props; const { t } = useTranslation(); const { shortcutList } = useAppSelector((state) => state.shortcut); const [state, setState] = useState({ @@ -38,12 +39,13 @@ const CreateShortcutDialog: React.FC = (props: Props) => { description: "", image: "", }, + ...initialShortcut, }, }); const [showAdditionalFields, setShowAdditionalFields] = useState(false); const [showOpenGraphMetadata, setShowOpenGraphMetadata] = useState(false); const [tag, setTag] = useState(""); - const tagSuggestions = shortcutList.map((shortcut) => shortcut.tags).flat(); + const tagSuggestions = uniq(shortcutList.map((shortcut) => shortcut.tags).flat()); const requestState = useLoading(false); const isCreating = isUndefined(shortcutId); diff --git a/frontend/web/src/pages/NotFound.tsx b/frontend/web/src/pages/NotFound.tsx new file mode 100644 index 0000000..9ebb1df --- /dev/null +++ b/frontend/web/src/pages/NotFound.tsx @@ -0,0 +1,62 @@ +import { Button } from "@mui/joy"; +import { useEffect, useState } from "react"; +import { useLocation } from "react-router-dom"; +import CreateShortcutDialog from "@/components/CreateShortcutDialog"; +import Icon from "@/components/Icon"; +import useNavigateTo from "@/hooks/useNavigateTo"; +import useUserStore from "@/stores/v1/user"; + +interface State { + showCreateShortcutButton: boolean; +} + +const NotFound = () => { + const location = useLocation(); + const navigateTo = useNavigateTo(); + const currentUser = useUserStore().getCurrentUser(); + const [state, setState] = useState({ + showCreateShortcutButton: false, + }); + const [showCreateShortcutDialog, setShowCreateShortcutDialog] = useState(false); + const params = new URLSearchParams(location.search); + + useEffect(() => { + const shortcut = params.get("shortcut"); + if (currentUser && shortcut) { + setState({ + ...state, + showCreateShortcutButton: true, + }); + } + }, []); + + return ( + <> +
+
+ +

404

+ {state.showCreateShortcutButton && ( + + )} +
+
+ + {showCreateShortcutDialog && ( + setShowCreateShortcutDialog(false)} + onConfirm={() => navigateTo("/")} + /> + )} + + ); +}; + +export default NotFound; diff --git a/frontend/web/src/routers/index.tsx b/frontend/web/src/routers/index.tsx index 19ce397..6bbe648 100644 --- a/frontend/web/src/routers/index.tsx +++ b/frontend/web/src/routers/index.tsx @@ -1,4 +1,5 @@ import { createBrowserRouter } from "react-router-dom"; +import NotFound from "@/pages/NotFound"; import SignIn from "@/pages/SignIn"; import SignUp from "@/pages/SignUp"; import SubscriptionSetting from "@/pages/SubscriptionSetting"; @@ -53,6 +54,10 @@ const router = createBrowserRouter([ }, ], }, + { + path: "*", + element: , + }, ], }, ]);