mirror of
https://github.com/aykhans/slash-e.git
synced 2025-04-20 22:07:15 +00:00
chore: add create shortcut button when not found
This commit is contained in:
parent
690e14e4ed
commit
0fd54426e6
@ -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)
|
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("failed to get shortcut, err: %s", err)).SetInternal(err)
|
||||||
}
|
}
|
||||||
if shortcut == nil {
|
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 {
|
if shortcut.Visibility != storepb.Visibility_PUBLIC {
|
||||||
userID, ok := c.Get(userIDContextKey).(int32)
|
userID, ok := c.Get(userIDContextKey).(int32)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Button, Divider, Input, Modal, ModalDialog, Radio, RadioGroup, Textarea } from "@mui/joy";
|
import { Button, Divider, Input, Modal, ModalDialog, Radio, RadioGroup, Textarea } from "@mui/joy";
|
||||||
import classnames from "classnames";
|
import classnames from "classnames";
|
||||||
import { isUndefined } from "lodash-es";
|
import { isUndefined, uniq } from "lodash-es";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { toast } from "react-hot-toast";
|
import { toast } from "react-hot-toast";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@ -11,6 +11,7 @@ import Icon from "./Icon";
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
shortcutId?: ShortcutId;
|
shortcutId?: ShortcutId;
|
||||||
|
initialShortcut?: Partial<Shortcut>;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onConfirm?: () => void;
|
onConfirm?: () => void;
|
||||||
}
|
}
|
||||||
@ -22,7 +23,7 @@ interface State {
|
|||||||
const visibilities: Visibility[] = ["PRIVATE", "WORKSPACE", "PUBLIC"];
|
const visibilities: Visibility[] = ["PRIVATE", "WORKSPACE", "PUBLIC"];
|
||||||
|
|
||||||
const CreateShortcutDialog: React.FC<Props> = (props: Props) => {
|
const CreateShortcutDialog: React.FC<Props> = (props: Props) => {
|
||||||
const { onClose, onConfirm, shortcutId } = props;
|
const { onClose, onConfirm, shortcutId, initialShortcut } = props;
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { shortcutList } = useAppSelector((state) => state.shortcut);
|
const { shortcutList } = useAppSelector((state) => state.shortcut);
|
||||||
const [state, setState] = useState<State>({
|
const [state, setState] = useState<State>({
|
||||||
@ -38,12 +39,13 @@ const CreateShortcutDialog: React.FC<Props> = (props: Props) => {
|
|||||||
description: "",
|
description: "",
|
||||||
image: "",
|
image: "",
|
||||||
},
|
},
|
||||||
|
...initialShortcut,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const [showAdditionalFields, setShowAdditionalFields] = useState<boolean>(false);
|
const [showAdditionalFields, setShowAdditionalFields] = useState<boolean>(false);
|
||||||
const [showOpenGraphMetadata, setShowOpenGraphMetadata] = useState<boolean>(false);
|
const [showOpenGraphMetadata, setShowOpenGraphMetadata] = useState<boolean>(false);
|
||||||
const [tag, setTag] = useState<string>("");
|
const [tag, setTag] = useState<string>("");
|
||||||
const tagSuggestions = shortcutList.map((shortcut) => shortcut.tags).flat();
|
const tagSuggestions = uniq(shortcutList.map((shortcut) => shortcut.tags).flat());
|
||||||
const requestState = useLoading(false);
|
const requestState = useLoading(false);
|
||||||
const isCreating = isUndefined(shortcutId);
|
const isCreating = isUndefined(shortcutId);
|
||||||
|
|
||||||
|
62
frontend/web/src/pages/NotFound.tsx
Normal file
62
frontend/web/src/pages/NotFound.tsx
Normal file
@ -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<State>({
|
||||||
|
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 (
|
||||||
|
<>
|
||||||
|
<div className="w-full h-full overflow-y-auto overflow-x-hidden bg-zinc-100 dark:bg-zinc-800">
|
||||||
|
<div className="w-full h-full flex flex-col justify-center items-center">
|
||||||
|
<Icon.Meh strokeWidth={1} className="w-20 h-auto opacity-80 dark:text-gray-300" />
|
||||||
|
<p className="mt-4 mb-8 text-4xl font-mono dark:text-gray-300">404</p>
|
||||||
|
{state.showCreateShortcutButton && (
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
startDecorator={<Icon.Plus className="w-5 h-auto" />}
|
||||||
|
onClick={() => setShowCreateShortcutDialog(true)}
|
||||||
|
>
|
||||||
|
Create shortcut
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{showCreateShortcutDialog && (
|
||||||
|
<CreateShortcutDialog
|
||||||
|
initialShortcut={{ name: params.get("shortcut") || "" }}
|
||||||
|
onClose={() => setShowCreateShortcutDialog(false)}
|
||||||
|
onConfirm={() => navigateTo("/")}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NotFound;
|
@ -1,4 +1,5 @@
|
|||||||
import { createBrowserRouter } from "react-router-dom";
|
import { createBrowserRouter } from "react-router-dom";
|
||||||
|
import NotFound from "@/pages/NotFound";
|
||||||
import SignIn from "@/pages/SignIn";
|
import SignIn from "@/pages/SignIn";
|
||||||
import SignUp from "@/pages/SignUp";
|
import SignUp from "@/pages/SignUp";
|
||||||
import SubscriptionSetting from "@/pages/SubscriptionSetting";
|
import SubscriptionSetting from "@/pages/SubscriptionSetting";
|
||||||
@ -53,6 +54,10 @@ const router = createBrowserRouter([
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "*",
|
||||||
|
element: <NotFound />,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user