This commit is contained in:
Philipinho
2025-04-12 17:59:00 +01:00
parent 16a253ec40
commit 8dff3e2240
16 changed files with 293 additions and 72 deletions

View File

@ -1,7 +1,7 @@
import { NodeViewProps, NodeViewWrapper } from "@tiptap/react";
import { ActionIcon, Anchor, Text } from "@mantine/core";
import { IconFileDescription } from "@tabler/icons-react";
import { Link, useParams } from "react-router-dom";
import { Link, useLocation, useParams } from "react-router-dom";
import { usePageQuery } from "@/features/page/queries/page-query.ts";
import {
buildPageUrl,
@ -20,6 +20,9 @@ export default function MentionView(props: NodeViewProps) {
isError,
} = usePageQuery({ pageId: entityType === "page" ? slugId : null });
const location = useLocation();
const isShareRoute = location.pathname.startsWith("/share");
const shareSlugUrl = buildSharedPageUrl({
shareId,
pageSlugId: slugId,
@ -38,7 +41,9 @@ export default function MentionView(props: NodeViewProps) {
<Anchor
component={Link}
fw={500}
to={shareId ? shareSlugUrl : buildPageUrl(spaceSlug, slugId, label)}
to={
isShareRoute ? shareSlugUrl : buildPageUrl(spaceSlug, slugId, label)
}
underline="never"
className={classes.pageMentionLink}
>

View File

@ -35,6 +35,7 @@ import {
import { formattedDate, timeAgo } from "@/lib/time.ts";
import MovePageModal from "@/features/page/components/move-page-modal.tsx";
import { useTimeAgo } from "@/hooks/use-time-ago.tsx";
import ShareModal from '@/features/share/components/share-modal.tsx';
interface PageHeaderMenuProps {
readOnly?: boolean;
@ -58,6 +59,8 @@ export default function PageHeaderMenu({ readOnly }: PageHeaderMenuProps) {
</Tooltip>
)}
<ShareModal/>
<Tooltip label={t("Comments")} openDelay={250} withArrow>
<ActionIcon
variant="default"

View File

@ -31,5 +31,9 @@ export const buildSharedPageUrl = (opts: {
pageTitle?: string;
}): string => {
const { shareId, pageSlugId, pageTitle } = opts;
if (!shareId) {
return `/share/p/${buildPageSlug(pageSlugId, pageTitle)}`;
}
return `/share/${shareId}/${buildPageSlug(pageSlugId, pageTitle)}`;
};

View File

@ -0,0 +1,88 @@
import {
Button,
Group,
MantineSize,
Popover,
Switch,
Text,
TextInput,
} from "@mantine/core";
import { IconWorld } from "@tabler/icons-react";
import React, { useState } from "react";
import { useShareStatusQuery } from "@/features/share/queries/share-query.ts";
import { useParams } from "react-router-dom";
import { extractPageSlugId } from "@/lib";
import { useTranslation } from "react-i18next";
import CopyTextButton from "@/components/common/copy.tsx";
export default function ShareModal() {
const { t } = useTranslation();
const { pageSlug } = useParams();
const { data } = useShareStatusQuery(extractPageSlugId(pageSlug));
const publicLink =
window.location.protocol +'//' + window.location.host +
"/share/" +
data?.["share"]?.["key"] +
"/" +
pageSlug;
return (
<Popover width={350} position="bottom" withArrow shadow="md">
<Popover.Target>
<Button
variant="default"
style={{ border: "none" }}
leftSection={<IconWorld size={20} stroke={1.5} />}
>
Share
</Button>
</Popover.Target>
<Popover.Dropdown>
<Group justify="space-between" wrap="nowrap" gap="xl">
<div>
<Text size="md">{t("Make page public")}</Text>
</div>
<ToggleShare isChecked={true}></ToggleShare>
</Group>
<Group my="sm" grow>
<TextInput
variant="filled"
value={publicLink}
pointer
readOnly
rightSection={<CopyTextButton text={publicLink} />}
/>
</Group>
</Popover.Dropdown>
</Popover>
);
}
interface PageWidthToggleProps {
isChecked: boolean;
size?: MantineSize;
label?: string;
}
export function ToggleShare({ isChecked, size, label }: PageWidthToggleProps) {
const { t } = useTranslation();
const [checked, setChecked] = useState(isChecked);
const handleChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
const value = event.currentTarget.checked;
setChecked(value);
};
return (
<Switch
size={size}
label={label}
labelPosition="left"
defaultChecked={checked}
onChange={handleChange}
aria-label={t("Toggle share")}
/>
);
}

View File

@ -1,8 +1,4 @@
import {
useMutation,
useQuery,
UseQueryResult,
} from "@tanstack/react-query";
import { useMutation, useQuery, UseQueryResult } from "@tanstack/react-query";
import { notifications } from "@mantine/notifications";
import { validate as isValidUuid } from "uuid";
import { useTranslation } from "react-i18next";
@ -14,6 +10,7 @@ import {
createShare,
deleteShare,
getShareInfo,
getShareStatus,
updateShare,
} from "@/features/share/services/share-service.ts";
import { IPage } from "@/features/page/types/page.types.ts";
@ -24,7 +21,20 @@ export function useShareQuery(
const query = useQuery({
queryKey: ["shares", shareInput],
queryFn: () => getShareInfo(shareInput),
enabled: !!shareInput.shareId,
enabled: !!shareInput.pageId,
staleTime: 5 * 60 * 1000,
});
return query;
}
export function useShareStatusQuery(
pageId: string,
): UseQueryResult<IPage, Error> {
const query = useQuery({
queryKey: ["share-status", pageId],
queryFn: () => getShareStatus(pageId),
enabled: !!pageId,
staleTime: 5 * 60 * 1000,
});

View File

@ -6,11 +6,21 @@ import {
IShareInfoInput,
} from "@/features/share/types/share.types.ts";
export async function getShares(data: ICreateShare): Promise<any> {
const req = await api.post<any>("/shares", data);
return req.data;
}
export async function createShare(data: ICreateShare): Promise<any> {
const req = await api.post<any>("/shares/create", data);
return req.data;
}
export async function getShareStatus(pageId: string): Promise<any> {
const req = await api.post<IPage>("/shares/status", { pageId });
return req.data;
}
export async function getShareInfo(
shareInput: Partial<IShareInfoInput>,
): Promise<IPage> {

View File

@ -1,10 +1,8 @@
export interface ICreateShare {
slugId: string; // share slugId
pageId: string;
includeSubPages?: boolean;
}
export interface IShareInfoInput {
shareId: string;
pageId: string;
}
}