Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const Public: Story = {
args: {
...commonArgs,
file,
isAdmin: false,
canManagePost: false,
},
argTypes: {
sharePublicLink: { action: 'share public click' },
Expand All @@ -29,7 +29,7 @@ export const Private: Story = {
privacyLabel: 'Post is private',
numberOfFiles: 5,
file,
isAdmin: true,
canManagePost: true,
},
argTypes: {
sharePublicLink: { action: 'share public click' },
Expand All @@ -42,7 +42,7 @@ export const NoImage: Story = {
args: {
...commonArgs,
privacyLabel: 'Files are private',
isAdmin: false,
canManagePost: false,
},
argTypes: {
sharePublicLink: { action: 'share public click' },
Expand All @@ -54,7 +54,7 @@ export const NoImage: Story = {
export const Draft: Story = {
args: {
...commonArgs,
isAdmin: true,
canManagePost: true,
draftLabel: 'Draft',
},
argTypes: {
Expand All @@ -70,7 +70,7 @@ export const DraftPrivate: Story = {
...commonArgs,
privacyLabel: 'Post is private',
numberOfFiles: 5,
isAdmin: true,
canManagePost: true,
draftLabel: 'Draft',
file,
},
Expand Down
6 changes: 3 additions & 3 deletions web-components/src/components/cards/PostCard/PostCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ interface PostCardProps {
author: User;
signers?: Array<User>;
privacyLabel?: string;
isAdmin?: boolean;
canManagePost?: boolean;
numberOfFiles?: number;
sharePublicLink: (ev: React.MouseEvent) => void;
sharePrivateLink: (ev: React.MouseEvent) => void;
Expand All @@ -47,7 +47,7 @@ export default function PostCard({
author,
signers,
privacyLabel,
isAdmin,
canManagePost,
numberOfFiles,
sharePublicLink,
sharePrivateLink,
Expand All @@ -71,7 +71,7 @@ export default function PostCard({
>
<ActionButton
draft={!!draftLabel}
isAdmin={isAdmin}
canManagePost={canManagePost}
sharePublicLink={sharePublicLink}
sharePrivateLink={sharePrivateLink}
onDelete={onDelete}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import React from 'react';
import { IconButton } from '@mui/material';

import {
Expand All @@ -10,17 +9,17 @@ import ShareIcon from '../../icons/ShareIcon';
const ActionButton = ({
publicPost,
draft,
isAdmin,
canManagePost,
sharePublicLink,
sharePrivateLink,
onDelete,
onEditDraft,
}: {
isAdmin?: boolean;
canManagePost?: boolean;
} & PostAdminButtonProps): JSX.Element => {
return (
<div className="z-[1] absolute top-5 right-5 lg:top-[15px] lg:right-[12px] cursor-pointer">
{isAdmin ? (
{canManagePost ? (
<PostAdminButton
publicPost={publicPost}
draft={draft}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { msg } from '@lingui/core/macro';
import { useLingui } from '@lingui/react';
import { Trans } from '@lingui/react/macro';

import { RegenModalProps } from 'web-components/src/components/modal';
import { SadBeeModal } from 'web-components/src/components/modal/SadBeeModal/SadBeeModal';
import { CancelButtonFooter } from 'web-components/src/components/organisms/CancelButtonFooter/CancelButtonFooter';
import { Body, Title } from 'web-components/src/components/typography';

type EditedDraftModalProps = {
onCancel: () => void;
onSubmit: () => void;
} & RegenModalProps;

export const EditedDraftModal = ({
onCancel,
onSubmit,
open,
onClose,
}: EditedDraftModalProps) => {
const { _ } = useLingui();
return (
<SadBeeModal open={open} onClose={onClose}>
<Title variant="h4" className="text-center my-20">
<Trans>
Someone made changes to this draft while you were editing.
</Trans>
</Title>
<Body size="lg" className="text-center mb-50">
<Trans>You will overwrite their changes if you continue.</Trans>
</Body>
<CancelButtonFooter
label={_(msg`overwrite & publish`)}
onCancel={onCancel}
onClick={onSubmit}
/>
</SadBeeModal>
);
};
70 changes: 66 additions & 4 deletions web-marketplace/src/components/organisms/PostFlow/PostFlow.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useCallback, useEffect, useRef, useState } from 'react';
import { msg } from '@lingui/core/macro';
import { useLingui } from '@lingui/react';
import { GeocodeFeature } from '@mapbox/mapbox-sdk/services/geocoding';
import { ContentHash_Graph } from '@regen-network/api/regen/data/v2/types';
Expand Down Expand Up @@ -43,6 +44,7 @@ import {
DRAFT_CREATED,
DRAFT_SAVED,
} from './PostFlow.constants';
import { EditedDraftModal } from './PostFlow.EditedDraftModal';
import { SignModal } from './PostFlow.SignModal';

type Props = {
Expand Down Expand Up @@ -82,6 +84,10 @@ export const PostFlow = ({
const { wallet } = useWallet();
const { activeAccount } = useAuth();
const [isFormModalOpen, setIsFormModalOpen] = useState(true);
const [isDraftEditedModalOpen, setIsDraftEditedModalOpen] = useState(false);
const [editedData, setEditedData] = useState<PostFormSchemaType | undefined>(
undefined,
);
const [iri, setIri] = useState<string | undefined>();
const { data: createdPostData, isFetching } = useQuery(
getPostQuery({
Expand All @@ -104,8 +110,9 @@ export const PostFlow = ({
const setErrorBannerTextAtom = useSetAtom(errorBannerTextAtom);
const setBannerText = useSetAtom(bannerTextAtom);
const draftPostIri = initialValues?.iri;
const draftPostId = initialValues?.id;

const onSubmit = useCallback(
const saveDataPost = useCallback(
async (data: PostFormSchemaType) => {
if (token) {
const files = data.files
Expand All @@ -126,9 +133,9 @@ export const PostFlow = ({
try {
await postData({
url: `${apiServerUrl}/marketplace/v1/posts${
draftPostIri ? `/${draftPostIri}` : ''
data?.iri ? `/${data.iri}` : ''
}`,
method: draftPostIri ? 'PUT' : 'POST',
method: data?.iri ? 'PUT' : 'POST',
data: {
projectId: offChainProjectId,
privacy: data.privacyType,
Expand Down Expand Up @@ -168,7 +175,6 @@ export const PostFlow = ({
},
[
token,
draftPostIri,
offChainProjectId,
retryCsrfRequest,
reactQueryClient,
Expand All @@ -177,6 +183,50 @@ export const PostFlow = ({
],
);

const onSubmit = useCallback(
async (data: PostFormSchemaType) => {
// Check if draft post has been updated in the meantime
if (draftPostId && initialValues?.updatedAt) {
try {
const resp = await fetch(
`${apiUri}/marketplace/v1/posts/by-id/${draftPostId}`,
{
method: 'GET',
credentials: 'include',
},
);
if (resp.status !== 200) {
throw new Error(
_(msg`Cannot get existing post: ${resp.statusText}`),
);
}
const existingPost: { iri: string; updatedAt: string } =
await resp.json();
if (
new Date(existingPost.updatedAt).getTime() !==
initialValues?.updatedAt.getTime()
) {
// We need to overwrite iri in case it has changed
setEditedData({ ...data, iri: existingPost.iri });
setIsDraftEditedModalOpen(true);
return;
}
} catch (e) {
setErrorBannerTextAtom(String(e));
return;
}
}
await saveDataPost(data);
},
[
saveDataPost,
setErrorBannerTextAtom,
draftPostId,
initialValues?.updatedAt,
_,
],
);

const fetchMsgAnchor = useFetchMsgAnchor({
projectSlug,
projectId,
Expand All @@ -187,6 +237,7 @@ export const PostFlow = ({

const hasAddress =
!!wallet?.address && activeAccount?.addr === wallet.address;

useEffect(() => {
if (iri && createdPostData && !isFetching) {
setIsFormModalOpen(false);
Expand Down Expand Up @@ -311,6 +362,17 @@ export const PostFlow = ({
bodyText={_(DISCARD_CHANGES_BODY)}
buttonText={_(DISCARD_CHANGES_BUTTON)}
/>
{editedData && (
<EditedDraftModal
open={isDraftEditedModalOpen}
onCancel={() => setIsDraftEditedModalOpen(false)}
onSubmit={async () => {
setIsDraftEditedModalOpen(false);
await saveDataPost(editedData);
}}
onClose={() => setIsDraftEditedModalOpen(false)}
/>
)}
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ type PostFormSchemaParams = {

export const getPostFormSchema = ({ requiredMessage }: PostFormSchemaParams) =>
z.object({
id: z.string().optional(),
iri: z.string().optional(),
title: z.string().max(POST_MAX_TITLE_LENGTH).min(1),
comment: z.string().min(1),
files: z.array(editFileFormSchema).optional(),
privacyType: z.custom<PostPrivacyType>(val => !!val, requiredMessage),
published: z.boolean(),
disallowFileDownloads: z.boolean().optional(),
updatedAt: z.date().optional(),
});

export type PostFormSchemaType = z.infer<ReturnType<typeof getPostFormSchema>>;
Original file line number Diff line number Diff line change
Expand Up @@ -68,25 +68,27 @@ type Props = {
post: Post;
index: number;
postsLength: number;
isAdmin: boolean;
adminAccountId?: string | null;
offChainProjectId?: string;
adminAddr?: string | null;
setDraftPost: UseStateSetter<Partial<PostFormSchemaType> | undefined>;
projectLocation: GeocodeFeature;
openCreatePostModal: () => void;
canManagePost: boolean;
canViewPost: boolean;
};
export const DataStreamPost = ({
offChainProjectId,
post,
index,
postsLength,
isAdmin,
adminAccountId,
adminAddr,
setDraftPost,
projectLocation,
openCreatePostModal,
canManagePost,
canViewPost,
}: Props) => {
const { _ } = useLingui();
const [selectedLanguage] = useAtom(selectedLanguageAtom);
Expand Down Expand Up @@ -196,7 +198,7 @@ export const DataStreamPost = ({
<TimelineConnector className="bg-grey-300 w-1" />
</TimelineSeparator>
<TimelineContent className="-mt-30 mb-30 pr-0 pl-0">
{post.contents && (post.privacy !== 'private' || isAdmin) && (
{post.contents && (post.privacy !== 'private' || canViewPost) && (
<PostCard
draftLabel={!post.published ? _(DRAFT) : undefined}
onClick={() =>
Expand Down Expand Up @@ -224,7 +226,7 @@ export const DataStreamPost = ({
timestamp: post.createdAt,
tag: creatorIsAdmin ? _(ADMIN) : undefined,
}}
isAdmin={isAdmin}
canManagePost={canManagePost}
sharePublicLink={() => {
copyTextToClipboard(
LINK_PREFIX
Expand All @@ -241,6 +243,8 @@ export const DataStreamPost = ({
preview={preview}
onEditDraft={() => {
setDraftPost({
id: post.id,
updatedAt: new Date(post.updatedAt),
iri: post.iri,
title: post.contents?.title,
comment: post.contents?.comment,
Expand All @@ -265,15 +269,15 @@ export const DataStreamPost = ({
linkComponent={Link}
/>
)}
{post.privacy === 'private' && !isAdmin && (
{post.privacy === 'private' && !canViewPost && (
<div className="flex items-center px-[16px] py-30 sm:p-30">
<LockIcon className="w-[18px] h-[18px]" />
<Subtitle size="lg">{_(PRIVATE_POST)}</Subtitle>
</div>
)}
</TimelineContent>
</TimelineItem>
{isAdmin && (
{canManagePost && (
<DeletePostWarningModal
onDelete={deletePost}
open={open}
Expand Down
Loading
Loading