From d8b3b2a2b180232c2c0390b1ab49d8b85458769c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rio=20Nunes?= Date: Sat, 26 Oct 2024 20:04:57 +0100 Subject: [PATCH 01/10] wip --- .../HowtoDescription/HowtoDescription.tsx | 19 ++- .../Research/Content/ResearchArticle.tsx | 133 +++++------------- .../Research/Content/ResearchDescription.tsx | 35 +++-- src/pages/Research/research.service.ts | 54 ++++++- src/routes/_.research.$slug._index.tsx | 39 ++++- src/stores/Research/research.store.tsx | 74 +--------- 6 files changed, 163 insertions(+), 191 deletions(-) diff --git a/src/pages/Howto/Content/Howto/HowtoDescription/HowtoDescription.tsx b/src/pages/Howto/Content/Howto/HowtoDescription/HowtoDescription.tsx index 4f51f0814a..cd3cb759b2 100644 --- a/src/pages/Howto/Content/Howto/HowtoDescription/HowtoDescription.tsx +++ b/src/pages/Howto/Content/Howto/HowtoDescription/HowtoDescription.tsx @@ -110,17 +110,14 @@ const HowtoDescription = ({ howto, loggedInUser, ...props }: IProps) => { }> {() => ( <> - {props.votedUsefulCount !== undefined && - howto.moderation === IModerationStatus.ACCEPTED && ( - - - - )} + {howto.moderation === IModerationStatus.ACCEPTED && ( + + )} )} diff --git a/src/pages/Research/Content/ResearchArticle.tsx b/src/pages/Research/Content/ResearchArticle.tsx index c27a40ca44..3ae80fe743 100644 --- a/src/pages/Research/Content/ResearchArticle.tsx +++ b/src/pages/Research/Content/ResearchArticle.tsx @@ -1,11 +1,10 @@ -import React, { useEffect } from 'react' -import { Link, useLocation, useParams } from '@remix-run/react' +import { useEffect } from 'react' +import { Link, useLocation } from '@remix-run/react' import { observer } from 'mobx-react' import { ArticleCallToAction, Button, FollowButton, - Loader, UsefulStatsButton, UserEngagementWrapper, } from 'oa-components' @@ -14,7 +13,6 @@ import { trackEvent } from 'src/common/Analytics' import { useContributorsData } from 'src/common/hooks/contributorsData' import { useCommonStores } from 'src/common/hooks/useCommonStores' import { Breadcrumbs } from 'src/pages/common/Breadcrumbs/Breadcrumbs' -import { NotFoundPage } from 'src/pages/NotFound/NotFound' import { getResearchCommentId, getResearchUpdateId, @@ -24,7 +22,6 @@ import { isAllowedToDeleteContent, isAllowedToEditContent, } from 'src/utils/helpers' -import { seoTagsUpdate, SeoTagsUpdateComponent } from 'src/utils/seo' import { Box, Flex } from 'theme-ui' import { @@ -34,19 +31,20 @@ import { import ResearchDescription from './ResearchDescription' import ResearchUpdate from './ResearchUpdate' -import type { IUploadedFileMeta, IUser } from 'oa-shared' +import type { IResearchDB, IUser } from 'oa-shared' const areCommentsVisible = (updateId) => { return updateId === getResearchUpdateId(window.location.hash) } -const ResearchArticle = observer(() => { - const { slug } = useParams() +type ResearchArticleProps = { + research: IResearchDB +} + +const ResearchArticle = observer(({ research }: ResearchArticleProps) => { const location = useLocation() const researchStore = useResearchStore() const { aggregationsStore } = useCommonStores().stores - const [isLoading, setIsLoading] = React.useState(true) - const item = researchStore.activeResearchItem const loggedInUser = researchStore.activeUser const moderateResearch = async (accepted: boolean) => { @@ -86,59 +84,26 @@ const ResearchArticle = observer(() => { section?.scrollIntoView({ behavior: 'smooth', block: 'start' }) } - useEffect(() => { - const init = async () => { - const researchItem = await researchStore.setActiveResearchItemBySlug(slug) - setIsLoading(false) - setTimeout(() => { - // Needed for browser and loading delay issues - scrollIntoRelevantSection() - }, 500) - - // Update SEO tags - if (researchItem) { - // Use whatever image used in most recent update for SEO image - const latestImage = researchItem?.updates - ?.map((u) => (u.images?.[0] as IUploadedFileMeta)?.downloadUrl) - .filter((url: string) => !!url) - .pop() - seoTagsUpdate({ - title: `${researchItem.title} - Research`, - description: researchItem.description, - imageUrl: latestImage, - }) - } - } - setIsLoading(true) - init() - - // Reset the store's active item and seo tags on component cleanup - return () => { - researchStore.setActiveResearchItemBySlug() - seoTagsUpdate({}) - } - }, [slug]) - useEffect(() => { scrollIntoRelevantSection() }, [location.hash]) const onFollowClick = (researchSlug: string) => { - if (!loggedInUser?.userName || !item) { + if (!loggedInUser?.userName || !research) { return null } let action: string - if (item.subscribers?.includes(loggedInUser?.userName || '')) { + if (research.subscribers?.includes(loggedInUser?.userName || '')) { researchStore.removeSubscriberFromResearchArticle( - item._id, + research._id, loggedInUser?.userName, ) action = 'Unsubscribed' } else { researchStore.addSubscriberToResearchArticle( - item._id, + research._id, loggedInUser?.userName, ) action = 'Subscribed' @@ -150,71 +115,51 @@ const ResearchArticle = observer(() => { }) } - const collaborators = Array.isArray(item?.collaborators) - ? item?.collaborators - : ((item?.collaborators as string | undefined)?.split(',') || []).filter( - Boolean, - ) + const collaborators = Array.isArray(research?.collaborators) + ? research?.collaborators + : ( + (research?.collaborators as string | undefined)?.split(',') || [] + ).filter(Boolean) const contributors = useContributorsData(collaborators || []) const isEditable = !!researchStore.activeUser && - !!item && - isAllowedToEditContent(item, researchStore.activeUser) + isAllowedToEditContent(research, researchStore.activeUser) const isDeletable = !!researchStore.activeUser && - !!item && - isAllowedToDeleteContent(item, researchStore.activeUser) - - const researchAuthor = item - ? { - userName: item._createdBy, - countryCode: item.creatorCountry, - isVerified: aggregationsStore.isVerified(item._createdBy), - } - : undefined - - if (isLoading) { - return - } + isAllowedToDeleteContent(research, researchStore.activeUser) - if (!item) { - return + const researchAuthor = { + userName: research._createdBy, + countryCode: research.creatorCountry, + isVerified: aggregationsStore.isVerified(research._createdBy), } - const research = { ...item } - return ( - - - + - onUsefulClick(item._id, item.slug, 'ResearchDescription') + onUsefulClick(research._id, research.slug, 'ResearchDescription') } - onFollowClick={() => onFollowClick(item.slug)} + onFollowClick={() => onFollowClick(research.slug)} contributors={contributors} subscribersCount={researchStore.subscribersCount} - commentsCount={item.totalCommentCount} + commentsCount={research.totalCommentCount} updatesCount={ - item.updates?.filter((u) => - researchUpdateStatusFilter(item, u, researchStore.activeUser), + research.updates?.filter((u) => + researchUpdateStatusFilter(research, u, researchStore.activeUser), ).length || 0 } /> @@ -226,15 +171,15 @@ const ResearchArticle = observer(() => { gap: [4, 6], }} > - {item && - getPublicUpdates(item, researchStore.activeUser).map( + {research && + getPublicUpdates(research, researchStore.activeUser).map( (update, index) => ( ), @@ -252,7 +197,7 @@ const ResearchArticle = observer(() => { author={researchAuthor} contributors={contributors} > - {item.moderation === IModerationStatus.ACCEPTED && ( + {research.moderation === IModerationStatus.ACCEPTED && ( { } onUsefulClick={async () => await onUsefulClick( - item._id, - item.slug, + research._id, + research.slug, 'ArticleCallToAction', ) } @@ -271,7 +216,7 @@ const ResearchArticle = observer(() => { onFollowClick(item.slug)} + onFollowClick={() => onFollowClick(research.slug)} /> )} @@ -280,7 +225,7 @@ const ResearchArticle = observer(() => { {isEditable && ( - + - + ) } diff --git a/packages/components/src/UsefulStatsButton/UsefulStatsButton.tsx b/packages/components/src/UsefulStatsButton/UsefulStatsButton.tsx index e29394243b..0698587768 100644 --- a/packages/components/src/UsefulStatsButton/UsefulStatsButton.tsx +++ b/packages/components/src/UsefulStatsButton/UsefulStatsButton.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react' +import { useMemo, useState } from 'react' import { useNavigate } from '@remix-run/react' import { Text, useThemeUI } from 'theme-ui' @@ -18,6 +18,7 @@ export interface IProps { export const UsefulStatsButton = (props: IProps) => { const { theme } = useThemeUI() as any const navigate = useNavigate() + const uuid = useMemo(() => crypto.randomUUID(), []) const [disabled, setDisabled] = useState() @@ -35,7 +36,7 @@ export const UsefulStatsButton = (props: IProps) => { <> - + ) } diff --git a/src/pages/Howto/Content/Howto/Howto.tsx b/src/pages/Howto/Content/Howto/Howto.tsx index 4d044246e3..6cbf644d0f 100644 --- a/src/pages/Howto/Content/Howto/Howto.tsx +++ b/src/pages/Howto/Content/Howto/Howto.tsx @@ -50,7 +50,6 @@ export const Howto = observer(({ howto }: HowtoParams) => { }, [howtoStore?.activeUser]) const onUsefulClick = async ( - howToSlug: string, vote: 'add' | 'delete', eventCategory: string, ) => { @@ -69,7 +68,7 @@ export const Howto = observer(({ howto }: HowtoParams) => { trackEvent({ category: eventCategory, action: vote === 'add' ? 'HowtoUseful' : 'HowtoUsefulRemoved', - label: howToSlug, + label: howto.slug, }) } @@ -79,17 +78,12 @@ export const Howto = observer(({ howto }: HowtoParams) => { - await onUsefulClick( - howto.slug, - voted ? 'delete' : 'add', - 'HowtoDescription', - ) + await onUsefulClick(voted ? 'delete' : 'add', 'HowtoDescription') } /> @@ -139,7 +133,6 @@ export const Howto = observer(({ howto }: HowtoParams) => { isLoggedIn={!!loggedInUser} onUsefulClick={() => onUsefulClick( - howto.slug, voted ? 'delete' : 'add', 'ArticleCallToAction', ) diff --git a/src/pages/Howto/Content/Howto/HowtoDescription/HowtoDescription.tsx b/src/pages/Howto/Content/Howto/HowtoDescription/HowtoDescription.tsx index cd3cb759b2..68866408a3 100644 --- a/src/pages/Howto/Content/Howto/HowtoDescription/HowtoDescription.tsx +++ b/src/pages/Howto/Content/Howto/HowtoDescription/HowtoDescription.tsx @@ -36,7 +36,6 @@ import type { IHowtoDB, ITag, IUser } from 'oa-shared' interface IProps { howto: IHowtoDB & { tagList?: ITag[] } loggedInUser: IUser | undefined - needsModeration: boolean commentsCount: number votedUsefulCount?: number verified?: boolean diff --git a/src/pages/Research/Content/ResearchArticle.tsx b/src/pages/Research/Content/ResearchArticle.tsx index 3ae80fe743..092755f938 100644 --- a/src/pages/Research/Content/ResearchArticle.tsx +++ b/src/pages/Research/Content/ResearchArticle.tsx @@ -1,4 +1,4 @@ -import { useEffect } from 'react' +import { useEffect, useState } from 'react' import { Link, useLocation } from '@remix-run/react' import { observer } from 'mobx-react' import { @@ -9,6 +9,8 @@ import { UserEngagementWrapper, } from 'oa-components' import { IModerationStatus } from 'oa-shared' +// eslint-disable-next-line import/no-unresolved +import { ClientOnly } from 'remix-utils/client-only' import { trackEvent } from 'src/common/Analytics' import { useContributorsData } from 'src/common/hooks/contributorsData' import { useCommonStores } from 'src/common/hooks/useCommonStores' @@ -46,20 +48,32 @@ const ResearchArticle = observer(({ research }: ResearchArticleProps) => { const researchStore = useResearchStore() const { aggregationsStore } = useCommonStores().stores const loggedInUser = researchStore.activeUser + const [subscribed, setSubscribed] = useState( + research.subscribers?.includes(loggedInUser?.userName || '') || false, + ) + const [subscribersCount, setSubscribersCount] = useState( + research.subscribers?.length || 0, + ) + const [voted, setVoted] = useState(false) + const [usefulCount, setUsefulCount] = useState( + research.votedUsefulBy?.length || 0, + ) - const moderateResearch = async (accepted: boolean) => { - const item = researchStore.activeResearchItem - if (item) { - item.moderation = accepted - ? IModerationStatus.ACCEPTED - : IModerationStatus.REJECTED - await researchStore.moderateResearch(item) + useEffect(() => { + // This could be improved if we can load the user profile server-side + if (researchStore?.activeUser) { + if (research.votedUsefulBy?.includes(researchStore.activeUser._id)) { + setVoted(true) + } + + if (research.subscribers?.includes(researchStore.activeUser._id)) { + setSubscribed(true) + } } - } + }, [researchStore?.activeUser]) const onUsefulClick = async ( - researchId: string, - researchSlug: string, + vote: 'add' | 'delete', eventCategory = 'Research', ) => { if (!loggedInUser?.userName) { @@ -67,12 +81,17 @@ const ResearchArticle = observer(({ research }: ResearchArticleProps) => { } // Trigger update without waiting - await researchStore.toggleUsefulByUser(researchId, loggedInUser?.userName) - const hasUserVotedUseful = researchStore.userVotedActiveResearchUseful + await researchStore.toggleUsefulByUser(research, loggedInUser?.userName) + setVoted((prev) => !prev) + + setUsefulCount((prev) => { + return vote === 'add' ? prev + 1 : prev - 1 + }) + trackEvent({ category: eventCategory, - action: hasUserVotedUseful ? 'ResearchUseful' : 'ResearchUsefulRemoved', - label: researchSlug, + action: vote === 'add' ? 'ResearchUseful' : 'ResearchUsefulRemoved', + label: research.slug, }) } @@ -95,7 +114,7 @@ const ResearchArticle = observer(({ research }: ResearchArticleProps) => { let action: string - if (research.subscribers?.includes(loggedInUser?.userName || '')) { + if (subscribed) { researchStore.removeSubscriberFromResearchArticle( research._id, loggedInUser?.userName, @@ -108,6 +127,11 @@ const ResearchArticle = observer(({ research }: ResearchArticleProps) => { ) action = 'Subscribed' } + + setSubscribersCount((prev) => prev + (subscribed ? -1 : 1)) + // toggle subscribed + setSubscribed((prev) => !prev) + trackEvent({ category: 'Research', action: action, @@ -142,20 +166,18 @@ const ResearchArticle = observer(({ research }: ResearchArticleProps) => { - onUsefulClick(research._id, research.slug, 'ResearchDescription') + onUsefulClick(voted ? 'delete' : 'add', 'ResearchDescription') } onFollowClick={() => onFollowClick(research.slug)} contributors={contributors} - subscribersCount={researchStore.subscribersCount} + subscribersCount={subscribersCount} commentsCount={research.totalCommentCount} updatesCount={ research.updates?.filter((u) => @@ -186,42 +208,43 @@ const ResearchArticle = observer(({ research }: ResearchArticleProps) => { )} - - - {researchAuthor && ( - }> + {() => ( + + - {research.moderation === IModerationStatus.ACCEPTED && ( - - await onUsefulClick( - research._id, - research.slug, - 'ArticleCallToAction', - ) - } - /> + {researchAuthor && ( + + {research.moderation === IModerationStatus.ACCEPTED && ( + + onUsefulClick( + voted ? 'delete' : 'add', + 'ArticleCallToAction', + ) + } + /> + )} + onFollowClick(research.slug)} + /> + )} - onFollowClick(research.slug)} - /> - - )} - - + + + )} + {isEditable && ( diff --git a/src/pages/Research/Content/ResearchDescription.tsx b/src/pages/Research/Content/ResearchDescription.tsx index 61bb50367e..836c6a5f04 100644 --- a/src/pages/Research/Content/ResearchDescription.tsx +++ b/src/pages/Research/Content/ResearchDescription.tsx @@ -25,21 +25,19 @@ import { Box, Card, Divider, Flex, Heading, Text } from 'theme-ui' import { ContentAuthorTimestamp } from '../../common/ContentAuthorTimestamp/ContentAuthorTimestamp' import { researchStatusColour } from '../researchHelpers' -import type { IResearch, ITag, IUser } from 'oa-shared' +import type { IResearch, IResearchDB, ITag, IUser } from 'oa-shared' interface IProps { research: IResearch.ItemDB & { tagList?: ITag[] } isEditable: boolean isDeletable: boolean loggedInUser: IUser | undefined - needsModeration: boolean votedUsefulCount?: number hasUserVotedUseful: boolean hasUserSubscribed: boolean subscribersCount: number commentsCount: number updatesCount: number - moderateResearch: (accepted: boolean) => void onUsefulClick: () => Promise onFollowClick: () => void contributors?: { userName: string; isVerified: boolean }[] @@ -60,19 +58,19 @@ const ResearchDescription = ({ const store = useResearchStore() - const handleDelete = async (_id: string) => { + const handleDelete = async (research: IResearchDB) => { try { - await store.deleteResearch(_id) + await store.deleteResearch(research._id) trackEvent({ category: 'Research', action: 'Deleted', - label: store.activeResearchItem?.title, + label: research.title, }) logger.debug( { category: 'Research', action: 'Deleted', - label: store.activeResearchItem?.title, + label: research.title, }, 'Research marked for deletion', ) @@ -136,27 +134,6 @@ const ResearchDescription = ({ )} - {props.needsModeration && - research.moderation === - IModerationStatus.AWAITING_MODERATION && ( - - - - - )} - - ) -}) + {isEditable && ( + + + + + + )} + + ) + }, +) export default ResearchArticle diff --git a/src/pages/Research/Content/ResearchUpdate.tsx b/src/pages/Research/Content/ResearchUpdate.tsx index 3185f0c0ff..3e3cf56236 100644 --- a/src/pages/Research/Content/ResearchUpdate.tsx +++ b/src/pages/Research/Content/ResearchUpdate.tsx @@ -1,4 +1,5 @@ -import { Link } from '@remix-run/react' +import { useMemo } from 'react' +import { Link, useLocation } from '@remix-run/react' import { Button, DisplayDate, @@ -8,6 +9,8 @@ import { Username, VideoPlayer, } from 'oa-components' +// eslint-disable-next-line import/no-unresolved +import { ClientOnly } from 'remix-utils/client-only' import { DownloadWrapper } from 'src/common/DownloadWrapper' import { useContributorsData } from 'src/common/hooks/contributorsData' import { useCommonStores } from 'src/common/hooks/useCommonStores' @@ -15,6 +18,7 @@ import { useResearchStore } from 'src/stores/Research/research.store' import { formatImagesForGallery } from 'src/utils/formatImageListForGallery' import { Box, Card, Flex, Heading, Text } from 'theme-ui' +import { getResearchUpdateId } from './helper' import { ResearchLinkToUpdate } from './ResearchLinkToUpdate' import { ResearchUpdateDiscussion } from './ResearchUpdateDiscussion' @@ -26,11 +30,11 @@ interface IProps { updateIndex: number isEditable: boolean slug: string - showComments: boolean } const ResearchUpdate = (props: IProps) => { - const { update, updateIndex, isEditable, slug, showComments } = props + const location = useLocation() + const { update, updateIndex, isEditable, slug } = props const { _id, _created, @@ -57,6 +61,11 @@ const ResearchUpdate = (props: IProps) => { const displayNumber = updateIndex + 1 const isDraft = status == 'draft' + const showComments = useMemo( + () => update._id === getResearchUpdateId(location.hash), + [location.hash], + ) + return ( { {videoUrl ? ( - + }> + {() => } + ) : ( { fileDownloadCount={downloadCount} /> - + }> + {() => ( + + )} + diff --git a/src/routes/_.research.$slug._index.tsx b/src/routes/_.research.$slug._index.tsx index bbcee02d25..5895c1f866 100644 --- a/src/routes/_.research.$slug._index.tsx +++ b/src/routes/_.research.$slug._index.tsx @@ -1,21 +1,27 @@ import { json } from '@remix-run/node' import { useLoaderData } from '@remix-run/react' +import { ResearchUpdateStatus } from 'oa-shared' import { NotFoundPage } from 'src/pages/NotFound/NotFound' import ResearchArticle from 'src/pages/Research/Content/ResearchArticle' import { researchService } from 'src/pages/Research/research.service' import { generateTags, mergeMeta } from 'src/utils/seo.utils' import type { LoaderFunctionArgs } from '@remix-run/node' -import type { IResearchDB } from 'oa-shared' +import type { IResearch, IResearchDB } from 'oa-shared' export async function loader({ params }: LoaderFunctionArgs) { const research = await researchService.getBySlug(params.slug as string) + const publicUpdates = + research?.updates.filter( + (x) => x.status !== ResearchUpdateStatus.DRAFT && x._deleted !== true, + ) || [] - return json({ research }) + return json({ research, publicUpdates }) } export const meta = mergeMeta(({ data }) => { const research = data?.research as IResearchDB + const publicUpdates = data?.publicUpdates as IResearch.UpdateDB[] if (!research) { return [] @@ -26,17 +32,18 @@ export const meta = mergeMeta(({ data }) => { return generateTags( title, research.description, - (research.updates?.at(0)?.images?.[0] as any)?.downloadUrl, + (publicUpdates?.at(0)?.images?.[0] as any)?.downloadUrl, ) }) export default function Index() { const data = useLoaderData() const research = data.research as IResearchDB + const publicUpdates = data.publicUpdates as IResearch.UpdateDB[] if (!research) { return } - return + return } diff --git a/src/routes/_.research.tsx b/src/routes/_.research.tsx index e6d66135d2..9f766be5c0 100644 --- a/src/routes/_.research.tsx +++ b/src/routes/_.research.tsx @@ -6,7 +6,7 @@ import { ResearchStoreContext, } from 'src/stores/Research/research.store' -export async function clientLoader() { +export async function loader() { return null } diff --git a/src/stores/Research/research.store.tsx b/src/stores/Research/research.store.tsx index 32eed4e012..e9658b70a9 100644 --- a/src/stores/Research/research.store.tsx +++ b/src/stores/Research/research.store.tsx @@ -47,8 +47,6 @@ export class ResearchStore extends ModuleStore { resetUpdateUploadStatus: action, lockResearchItem: action, unlockResearchItem: action, - lockResearchUpdate: action, - unlockResearchUpdate: action, }) } @@ -421,47 +419,33 @@ export class ResearchStore extends ModuleStore { } } - public async lockResearchUpdate( - item: IResearchDB, + public async toggleLockResearchUpdate( + researchId: string, username: string, updateId: string, + lock: boolean, ) { - if (item) { - const dbRef = this.db - .collection(COLLECTION_NAME) - .doc(item._id) - const updateIndex = item.updates.findIndex((upd) => upd._id === updateId) - const newItem = { - ...item, - updates: [...item.updates], - } + const dbRef = this.db + .collection(COLLECTION_NAME) + .doc(researchId) - if (updateIndex && newItem.updates[updateIndex]) { - newItem.updates[updateIndex].locked = { - by: username, - at: new Date().toISOString(), - } - } - await this._updateResearchItem(dbRef, newItem) + const item = toJS(await dbRef.get('server')) as IResearchDB + const updateIndex = item.updates.findIndex((upd) => upd._id === updateId) + const updatedItem = { + ...item, + updates: [...item.updates], } - } - - public async unlockResearchUpdate(item: IResearchDB, updateId: string) { - if (item) { - const dbRef = this.db - .collection(COLLECTION_NAME) - .doc(item._id) - const updateIndex = item.updates.findIndex((upd) => upd._id === updateId) - const newItem = { - ...item, - updates: [...item.updates], - } - if (newItem.updates[updateIndex]) { - newItem.updates[updateIndex].locked = null - } - await this._updateResearchItem(dbRef, newItem) + if (updatedItem.updates[updateIndex]) { + updatedItem.updates[updateIndex].locked = lock + ? { + by: username, + at: new Date().toISOString(), + } + : null } + + await dbRef.set(updatedItem) } private async _setCollaborators( From aa246dbffce90bc2e2428bdb6db0eae2c40bd183 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rio=20Nunes?= Date: Sun, 27 Oct 2024 14:19:00 +0000 Subject: [PATCH 06/10] fix: tests --- .../Content/Common/ResearchUpdate.form.test.tsx | 8 ++++++-- src/pages/Research/Content/ResearchArticle.test.tsx | 13 +++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/pages/Research/Content/Common/ResearchUpdate.form.test.tsx b/src/pages/Research/Content/Common/ResearchUpdate.form.test.tsx index 2b65f900fd..b040013c85 100644 --- a/src/pages/Research/Content/Common/ResearchUpdate.form.test.tsx +++ b/src/pages/Research/Content/Common/ResearchUpdate.form.test.tsx @@ -4,7 +4,10 @@ import { createMemoryRouter, RouterProvider } from 'react-router-dom' import { createRoutesFromElements, Route } from '@remix-run/react' import { render } from '@testing-library/react' import { ThemeProvider } from '@theme-ui/core' -import { FactoryResearchItemUpdate } from 'src/test/factories/ResearchItem' +import { + FactoryResearchItem, + FactoryResearchItemUpdate, +} from 'src/test/factories/ResearchItem' import { testingThemeStyles } from 'src/test/utils/themeUtils' import { describe, expect, it, vi } from 'vitest' @@ -43,7 +46,7 @@ vi.mock('src/stores/Research/research.store', () => { Complete: false, }, isTitleThatReusesSlug: vi.fn(), - unlockResearchUpdate: vi.fn(), + toggleLockResearchUpdate: vi.fn(), }), } }) @@ -86,6 +89,7 @@ const getWrapper = (formValues, parentType, navProps) => { index element={ { FactoryResearchItemUpdate({ title: 'Research Update #2', collaborators: null!, - status: ResearchUpdateStatus.PUBLISHED, + status: ResearchUpdateStatus.DRAFT, _deleted: false, }), FactoryResearchItemUpdate({ @@ -444,7 +444,16 @@ const getWrapper = (research: IResearchDB) => { } + element={ + + x._deleted !== true && + x.status === ResearchUpdateStatus.PUBLISHED, + )} + /> + } />, ), { From 8eda30aee7d2c0b83813e7605c70cbcbd2913486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rio=20Nunes?= Date: Sun, 27 Oct 2024 14:39:27 +0000 Subject: [PATCH 07/10] fix: edit update and tests --- src/pages/Research/Content/ResearchArticle.test.tsx | 1 + src/pages/Research/Content/ResearchArticle.tsx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/Research/Content/ResearchArticle.test.tsx b/src/pages/Research/Content/ResearchArticle.test.tsx index 9d6a70f18a..b93f81b489 100644 --- a/src/pages/Research/Content/ResearchArticle.test.tsx +++ b/src/pages/Research/Content/ResearchArticle.test.tsx @@ -257,6 +257,7 @@ describe('Research Article', () => { _modified: _created, title: 'A title', description: 'A description', + status: ResearchUpdateStatus.PUBLISHED, }) ;(useResearchStore as Mock).mockReturnValue(mockResearchStore) // Act diff --git a/src/pages/Research/Content/ResearchArticle.tsx b/src/pages/Research/Content/ResearchArticle.tsx index 5cbad0e8d6..1a51bff9e6 100644 --- a/src/pages/Research/Content/ResearchArticle.tsx +++ b/src/pages/Research/Content/ResearchArticle.tsx @@ -208,7 +208,7 @@ const ResearchArticle = observer( update={update} key={update._id} updateIndex={index} - isEditable={false} + isEditable={isEditable} slug={research.slug} /> ))} From b0d0063a843d48e6cc5c62db3ef37c1c673b2e66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rio=20Nunes?= Date: Thu, 31 Oct 2024 18:56:35 +0000 Subject: [PATCH 08/10] fix: don't use crypto api --- packages/components/src/FollowButton/FollowButton.tsx | 2 +- .../components/src/UsefulStatsButton/UsefulStatsButton.tsx | 2 +- packages/cypress/src/integration/questions/write.spec.ts | 4 ++-- packages/cypress/src/integration/research/write.spec.ts | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/components/src/FollowButton/FollowButton.tsx b/packages/components/src/FollowButton/FollowButton.tsx index 2f704a7732..dfa3291415 100644 --- a/packages/components/src/FollowButton/FollowButton.tsx +++ b/packages/components/src/FollowButton/FollowButton.tsx @@ -16,7 +16,7 @@ export interface IProps { export const FollowButton = (props: IProps) => { const { hasUserSubscribed, isLoggedIn, onFollowClick, sx } = props const navigate = useNavigate() - const uuid = useMemo(() => crypto.randomUUID(), []) + const uuid = useMemo(() => (Math.random() * 16).toString(), []) return ( <> diff --git a/packages/components/src/UsefulStatsButton/UsefulStatsButton.tsx b/packages/components/src/UsefulStatsButton/UsefulStatsButton.tsx index 0698587768..f03659919e 100644 --- a/packages/components/src/UsefulStatsButton/UsefulStatsButton.tsx +++ b/packages/components/src/UsefulStatsButton/UsefulStatsButton.tsx @@ -18,7 +18,7 @@ export interface IProps { export const UsefulStatsButton = (props: IProps) => { const { theme } = useThemeUI() as any const navigate = useNavigate() - const uuid = useMemo(() => crypto.randomUUID(), []) + const uuid = useMemo(() => (Math.random() * 16).toString(), []) const [disabled, setDisabled] = useState() diff --git a/packages/cypress/src/integration/questions/write.spec.ts b/packages/cypress/src/integration/questions/write.spec.ts index 2b0f48df87..28a8323af3 100644 --- a/packages/cypress/src/integration/questions/write.spec.ts +++ b/packages/cypress/src/integration/questions/write.spec.ts @@ -5,7 +5,7 @@ const item = questions[0] describe('[Question]', () => { describe('[Create a question]', () => { - const initialRandomId = crypto.randomUUID().slice(0, 8) + const initialRandomId = (Math.random() * 16).toString() const initialTitle = initialRandomId + ' Health cost of plastic?' const initialExpectedSlug = initialRandomId + '-health-cost-of-plastic' const initialQuestionDescription = @@ -13,7 +13,7 @@ describe('[Question]', () => { const category = 'exhibition' const tag1 = 'product' const tag2 = 'workshop' - const updatedRandomId = crypto.randomUUID().slice(0, 8) + const updatedRandomId = (Math.random() * 16).toString() const updatedTitle = updatedRandomId + ' Real health cost of plastic?' const updatedExpectedSlug = updatedRandomId + '-real-health-cost-of-plastic' const updatedQuestionDescription = `${initialQuestionDescription} and super awesome goggles` diff --git a/packages/cypress/src/integration/research/write.spec.ts b/packages/cypress/src/integration/research/write.spec.ts index ff0bf84946..6a77cd0bed 100644 --- a/packages/cypress/src/integration/research/write.spec.ts +++ b/packages/cypress/src/integration/research/write.spec.ts @@ -154,7 +154,7 @@ describe('[Research]', () => { }) it('[Any PP user]', () => { - const randomId = crypto.randomUUID().slice(0, 8) + const randomId = (Math.random() * 16).toString() const title = randomId + ' PP plastic stuff' const expectSlug = randomId + '-pp-plastic-stuff' const description = 'Bespoke research topic' @@ -255,7 +255,7 @@ describe('[Research]', () => { describe('[Displays draft updates for Author]', () => { it('[By Authenticated]', () => { - const randomId = crypto.randomUUID().slice(0, 8) + const randomId = (Math.random() * 16).toString() const updateTitle = `${randomId} Create a research update` const updateDescription = 'This is the description for the update.' const updateVideoUrl = 'http://youtube.com/watch?v=sbcWY7t-JX8' From 7a2a11c3f2a0bc460c7287ac0971390bccf7748f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rio=20Nunes?= Date: Thu, 31 Oct 2024 23:17:49 +0000 Subject: [PATCH 09/10] fix: tests --- packages/cypress/src/integration/questions/write.spec.ts | 5 +++-- packages/cypress/src/integration/research/write.spec.ts | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/cypress/src/integration/questions/write.spec.ts b/packages/cypress/src/integration/questions/write.spec.ts index 28a8323af3..fc4dd65b45 100644 --- a/packages/cypress/src/integration/questions/write.spec.ts +++ b/packages/cypress/src/integration/questions/write.spec.ts @@ -1,11 +1,12 @@ import { MOCK_DATA } from '../../data' +import { generateAlphaNumeric } from '../../utils/TestUtils' const questions = Object.values(MOCK_DATA.questions) const item = questions[0] describe('[Question]', () => { describe('[Create a question]', () => { - const initialRandomId = (Math.random() * 16).toString() + const initialRandomId = generateAlphaNumeric(8) const initialTitle = initialRandomId + ' Health cost of plastic?' const initialExpectedSlug = initialRandomId + '-health-cost-of-plastic' const initialQuestionDescription = @@ -13,7 +14,7 @@ describe('[Question]', () => { const category = 'exhibition' const tag1 = 'product' const tag2 = 'workshop' - const updatedRandomId = (Math.random() * 16).toString() + const updatedRandomId = generateAlphaNumeric(8) const updatedTitle = updatedRandomId + ' Real health cost of plastic?' const updatedExpectedSlug = updatedRandomId + '-real-health-cost-of-plastic' const updatedQuestionDescription = `${initialQuestionDescription} and super awesome goggles` diff --git a/packages/cypress/src/integration/research/write.spec.ts b/packages/cypress/src/integration/research/write.spec.ts index 6a77cd0bed..978ba11130 100644 --- a/packages/cypress/src/integration/research/write.spec.ts +++ b/packages/cypress/src/integration/research/write.spec.ts @@ -2,6 +2,7 @@ import { faker } from '@faker-js/faker' import { RESEARCH_TITLE_MIN_LENGTH } from '../../../../../src/pages/Research/constants' import { + generateAlphaNumeric, generateNewUserDetails, setIsPreciousPlastic, } from '../../utils/TestUtils' @@ -154,7 +155,7 @@ describe('[Research]', () => { }) it('[Any PP user]', () => { - const randomId = (Math.random() * 16).toString() + const randomId = generateAlphaNumeric(8) const title = randomId + ' PP plastic stuff' const expectSlug = randomId + '-pp-plastic-stuff' const description = 'Bespoke research topic' @@ -255,7 +256,7 @@ describe('[Research]', () => { describe('[Displays draft updates for Author]', () => { it('[By Authenticated]', () => { - const randomId = (Math.random() * 16).toString() + const randomId = generateAlphaNumeric(8) const updateTitle = `${randomId} Create a research update` const updateDescription = 'This is the description for the update.' const updateVideoUrl = 'http://youtube.com/watch?v=sbcWY7t-JX8' From 0fc6c41072183c92fcf84e23980bac15a05c85b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rio=20Nunes?= Date: Thu, 31 Oct 2024 23:56:14 +0000 Subject: [PATCH 10/10] fix: tests --- packages/cypress/src/integration/questions/write.spec.ts | 4 ++-- packages/cypress/src/integration/research/write.spec.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/cypress/src/integration/questions/write.spec.ts b/packages/cypress/src/integration/questions/write.spec.ts index fc4dd65b45..f5c363c981 100644 --- a/packages/cypress/src/integration/questions/write.spec.ts +++ b/packages/cypress/src/integration/questions/write.spec.ts @@ -6,7 +6,7 @@ const item = questions[0] describe('[Question]', () => { describe('[Create a question]', () => { - const initialRandomId = generateAlphaNumeric(8) + const initialRandomId = generateAlphaNumeric(8).toLowerCase() const initialTitle = initialRandomId + ' Health cost of plastic?' const initialExpectedSlug = initialRandomId + '-health-cost-of-plastic' const initialQuestionDescription = @@ -14,7 +14,7 @@ describe('[Question]', () => { const category = 'exhibition' const tag1 = 'product' const tag2 = 'workshop' - const updatedRandomId = generateAlphaNumeric(8) + const updatedRandomId = generateAlphaNumeric(8).toLowerCase() const updatedTitle = updatedRandomId + ' Real health cost of plastic?' const updatedExpectedSlug = updatedRandomId + '-real-health-cost-of-plastic' const updatedQuestionDescription = `${initialQuestionDescription} and super awesome goggles` diff --git a/packages/cypress/src/integration/research/write.spec.ts b/packages/cypress/src/integration/research/write.spec.ts index 978ba11130..6d36190635 100644 --- a/packages/cypress/src/integration/research/write.spec.ts +++ b/packages/cypress/src/integration/research/write.spec.ts @@ -155,7 +155,7 @@ describe('[Research]', () => { }) it('[Any PP user]', () => { - const randomId = generateAlphaNumeric(8) + const randomId = generateAlphaNumeric(8).toLowerCase() const title = randomId + ' PP plastic stuff' const expectSlug = randomId + '-pp-plastic-stuff' const description = 'Bespoke research topic' @@ -256,7 +256,7 @@ describe('[Research]', () => { describe('[Displays draft updates for Author]', () => { it('[By Authenticated]', () => { - const randomId = generateAlphaNumeric(8) + const randomId = generateAlphaNumeric(8).toLowerCase() const updateTitle = `${randomId} Create a research update` const updateDescription = 'This is the description for the update.' const updateVideoUrl = 'http://youtube.com/watch?v=sbcWY7t-JX8'