diff --git a/.storybook/main.ts b/.storybook/main.ts index 29eb40d98..b1d8c4716 100644 --- a/.storybook/main.ts +++ b/.storybook/main.ts @@ -1,3 +1,6 @@ +import path from 'path'; +import { readdirSync } from 'fs'; +import type { InlineConfig, Plugin } from 'vite'; import type { StorybookConfig } from '@storybook/react-vite'; const config: StorybookConfig = { @@ -9,11 +12,80 @@ const config: StorybookConfig = { '@storybook/addon-controls', '@storybook/addon-viewport', '@storybook/addon-toolbars', - '@storybook/addon-a11y', ], framework: '@storybook/react-vite', staticDirs: ['../static'], + viteFinal: async (config) => { + config.plugins?.push( + assetPlugin(config, { + markup: `[ICONS]`, + exclude: [/.*stories.*/], + assetDir: 'src/v4/icons', + storyFileName: 'icons.stories.tsx', + }), + ); + return config; + }, }; export default config; + +const assetPlugin: ( + config: InlineConfig, + options: { + assetDir: string; + storyFileName: string; + exclude?: Array; + markup: string | RegExp; + }, +) => Plugin = (config, { storyFileName, assetDir, exclude, markup }) => { + return { + enforce: 'pre', + name: 'vite-plugin-v4-icons', + transform(code, id) { + const rootDir = config.root!; + + if (id.includes(storyFileName)) { + let icons = '', + imports = ''; + readdirSync(path.join(rootDir, assetDir)).forEach((file) => { + if (file.match(/.*\.(tsx)/) && exclude?.every((ex) => !file.match(ex))) { + const fileName = file.replace(/.tsx/, ''); + const source = { + relativePath: path.join(assetDir.replace(/.*src\//, ''), fileName), + path: path.join(rootDir, assetDir, file), + }; + + // eslint-disable-next-line @typescript-eslint/no-var-requires + const exportedAssets = require(source.path!); + const entries = Object.entries(exportedAssets); + + entries.map(([key, _]) => { + const componentName = key === 'default' ? fileName : key; + imports += + key == 'default' + ? `import ${fileName} from "src/${source?.relativePath}";\n` + : `import {${key}} from "src/${source?.relativePath}";\n`; + icons += ` + + `; + }); + } + }); + + code = imports + code.replace(markup, icons); + } + return code; + }, + }; +}; diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e9e42837..0b705c34e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## 4.0.0-beta.16 (2024-10-25) + ## 4.0.0-beta.15 (2024-10-04) ## 4.0.0-beta.13 (2024-09-19) diff --git a/package.json b/package.json index 5c25d280d..7bde9c4b3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@amityco/ui-kit-open-source", - "version": "4.0.0-beta.15", + "version": "4.0.0-beta.16", "engines": { "node": ">=20", "pnpm": "9" diff --git a/src/core/components/Modal/styles.tsx b/src/core/components/Modal/styles.tsx index 98f3543ec..3e4fed3f3 100644 --- a/src/core/components/Modal/styles.tsx +++ b/src/core/components/Modal/styles.tsx @@ -2,7 +2,7 @@ import React, { ReactNode } from 'react'; import styled, { css } from 'styled-components'; import { Close } from '~/icons'; -export const CloseIcon = styled(Close).attrs<{ icon?: ReactNode }>({ width: 18, height: 18 })` +export const CloseIcon = styled(Close).attrs<{ icon?: ReactNode }>({ width: 20, height: 20 })` padding: 0 6px; cursor: pointer; margin-left: auto; diff --git a/src/helpers/utils.ts b/src/helpers/utils.ts index 9165c828f..c74152baa 100644 --- a/src/helpers/utils.ts +++ b/src/helpers/utils.ts @@ -6,8 +6,14 @@ import { } from '@amityco/ts-sdk'; import isEmpty from 'lodash/isEmpty'; -export type Mentioned = { userId: string; length: number; index: number; type: string }; -export type Mentionees = Parameters[1]['mentionees']; +export type Mentioned = { + userId: string; + length: number; + index: number; + type: string; + displayName: string; +}; +export type Mentionees = Amity.UserMention[]; export type Metadata = { mentioned?: Mentioned[]; }; @@ -116,6 +122,7 @@ export function extractMetadata( length: displayName.length - AT_SIGN_LENGTH, type: 'user', userId: id, + displayName, })), ]; @@ -160,3 +167,26 @@ export function parseMentionsMarkup( export function isNonNullable(value: TValue | undefined | null): value is TValue { return value != null; } + +export function reconstructMentions( + metadata?: Metadata, + mentionees?: Mentionees, +): { plainTextIndex: number; id: string; display: string }[] { + if (!metadata?.mentioned || mentionees?.length === 0) { + return []; + } + + const userIds = mentionees?.find((mentionee) => mentionee.type === 'user')?.userIds || []; + + return metadata?.mentioned?.map((mention, index) => { + const id = userIds[index]; + const displayName = mention.displayName; + const display = '@' + (displayName ?? id); + + return { + plainTextIndex: mention.index, + id, + display, + }; + }); +} diff --git a/src/social/components/post/Editor/index.tsx b/src/social/components/post/Editor/index.tsx index 3e85556c2..e02cd6b53 100644 --- a/src/social/components/post/Editor/index.tsx +++ b/src/social/components/post/Editor/index.tsx @@ -6,20 +6,19 @@ import { PostEditorContainer, Footer, ContentContainer, PostButton } from './sty import { usePostEditor } from './usePostEditor'; interface PostEditorProps { - postId?: string; + post: Amity.Post; onSave: () => void; className?: string; placeholder?: string; } const PostEditor = ({ - postId, + post, placeholder = "What's going on...", className, onSave, }: PostEditorProps) => { const { - post, markup, onChange, queryMentionees, @@ -30,7 +29,7 @@ const PostEditor = ({ isEmpty, handleSave, } = usePostEditor({ - postId, + post, onSave, }); diff --git a/src/social/components/post/Editor/usePostEditor.ts b/src/social/components/post/Editor/usePostEditor.ts index 7bd75a153..af05de098 100644 --- a/src/social/components/post/Editor/usePostEditor.ts +++ b/src/social/components/post/Editor/usePostEditor.ts @@ -1,12 +1,11 @@ import { PostRepository } from '@amityco/ts-sdk'; import { useMemo, useState } from 'react'; -import { parseMentionsMarkup } from '~/helpers/utils'; +import { parseMentionsMarkup, reconstructMentions } from '~/helpers/utils'; import usePost from '~/social/hooks/usePost'; import usePostByIds from '~/social/hooks/usePostByIds'; import useSocialMention from '~/social/hooks/useSocialMention'; -export const usePostEditor = ({ postId, onSave }: { postId?: string; onSave: () => void }) => { - const post = usePost(postId); +export const usePostEditor = ({ post, onSave }: { post: Amity.Post; onSave: () => void }) => { const initialChildrenPosts = usePostByIds(post?.children); const { text, markup, mentions, mentionees, metadata, clearAll, onChange, queryMentionees } = useSocialMention({ @@ -18,6 +17,7 @@ export const usePostEditor = ({ postId, onSave }: { postId?: string; onSave: () typeof post?.data === 'string' ? post?.data : (post?.data as Amity.ContentDataText)?.text, post?.metadata, ), + remoteMentions: reconstructMentions(post?.metadata, post?.mentionees), }); // List of the children posts removed - these will be deleted on save. diff --git a/src/social/components/post/Post/DefaultPostRenderer.tsx b/src/social/components/post/Post/DefaultPostRenderer.tsx index 3b29c0093..71619d650 100644 --- a/src/social/components/post/Post/DefaultPostRenderer.tsx +++ b/src/social/components/post/Post/DefaultPostRenderer.tsx @@ -320,13 +320,13 @@ const DefaultPostRenderer = (props: DefaultPostRendererProps) => { )} - {isEditing && ( + {isEditing && post && ( - + )} diff --git a/src/social/hooks/useSocialMention.ts b/src/social/hooks/useSocialMention.ts index c107a6f4f..25f2fe3fb 100644 --- a/src/social/hooks/useSocialMention.ts +++ b/src/social/hooks/useSocialMention.ts @@ -8,6 +8,7 @@ interface UseSocialMentionProps { targetType?: 'user' | 'community' | string; remoteText?: string; remoteMarkup?: string; + remoteMentions?: { plainTextIndex: number; id: string; display: string }[]; } export type QueryMentioneesFnType = (query?: string) => Promise< @@ -24,15 +25,15 @@ const useSocialMention = ({ targetType, remoteText, remoteMarkup, + remoteMentions = [], }: UseSocialMentionProps) => { const isCommunityFeed = targetType === 'community'; const community = useCommunity(targetId); const [text, setText] = useState(remoteText ?? ''); const [markup, setMarkup] = useState(remoteMarkup ?? remoteText); - const [mentions, setMentions] = useState< - { plainTextIndex: number; id: string; display: string }[] - >([]); + const [mentions, setMentions] = + useState<{ plainTextIndex: number; id: string; display: string }[]>(remoteMentions); useEffect(() => { setText(remoteText || ''); diff --git a/src/v4/icons/icons.stories.tsx b/src/v4/icons/icons.stories.tsx new file mode 100644 index 000000000..8ab6bd933 --- /dev/null +++ b/src/v4/icons/icons.stories.tsx @@ -0,0 +1,28 @@ +import React from 'react'; +import styles from './icons.style.module.css'; + +export default { + title: 'V4/Icons', +}; + +export const Default = { + render: () => { + return ( +
{ + if (e.target instanceof HTMLButtonElement) { + const iconName = e.target.getAttribute('data-name'); + if (iconName) { + navigator.clipboard.writeText(iconName).then(() => { + alert(`${iconName} copied.`); + }); + } + } + }} + > + [ICONS] +
+ ); + }, +}; diff --git a/src/v4/icons/icons.style.module.css b/src/v4/icons/icons.style.module.css new file mode 100644 index 000000000..cb2cbb705 --- /dev/null +++ b/src/v4/icons/icons.style.module.css @@ -0,0 +1,26 @@ +.container { + gap: 2rem; + width: 100%; + padding: 3rem; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr)); + background: var(--asc-color-background-default); +} + +.container button { + width: 100%; + padding: 1rem; + display: flex; + cursor: pointer; + align-items: center; + border-radius: 0.5rem; + flex-direction: column; + justify-content: center; + color: var(--asc-color-base-default); + background: var(--asc-color-secondary-shade5); + border: 1px solid var(--asc-color-secondary-shade4); +} + +.container button svg { + fill: var(--asc-color-base-default); +} diff --git a/src/v4/social/components/Comment/Comment.tsx b/src/v4/social/components/Comment/Comment.tsx index 303a515be..2b469b1b3 100644 --- a/src/v4/social/components/Comment/Comment.tsx +++ b/src/v4/social/components/Comment/Comment.tsx @@ -248,7 +248,9 @@ export const Comment = ({ componentId={componentId} timestamp={comment.createdAt} /> - {comment.createdAt !== comment.editedAt && ' (edited)'} + + {comment.createdAt !== comment.editedAt && ' (edited)'} +
diff --git a/src/v4/social/components/CommentComposer/CommentComposer.tsx b/src/v4/social/components/CommentComposer/CommentComposer.tsx index 82a8ed25d..1e9d6a5e1 100644 --- a/src/v4/social/components/CommentComposer/CommentComposer.tsx +++ b/src/v4/social/components/CommentComposer/CommentComposer.tsx @@ -175,7 +175,7 @@ export const CommentComposer = ({ data-qa-anchor={`${pageId}/${componentId}/comment_composer_post`} isDisabled={!textValue?.data?.text} className={styles.commentComposer__button} - onPress={() => mutateAsync({ params: textValue })} + onPressStart={() => mutateAsync({ params: textValue })} > Post diff --git a/src/v4/social/components/CommentComposer/CommentInput.tsx b/src/v4/social/components/CommentComposer/CommentInput.tsx index 68209e474..49041c5b3 100644 --- a/src/v4/social/components/CommentComposer/CommentInput.tsx +++ b/src/v4/social/components/CommentComposer/CommentInput.tsx @@ -177,6 +177,9 @@ export const CommentInput = forwardRef( const root = $getRoot(); root.clear(); }); + setTimeout(() => { + editorRef.current?.blur(); + }, 500); }; useImperativeHandle(ref, () => ({ @@ -202,7 +205,6 @@ export const CommentInput = forwardRef( }} >
( } > } + contentEditable={ + + } placeholder={ placehoder ?
{placehoder}
: null } diff --git a/src/v4/social/components/PostContent/PostContent.tsx b/src/v4/social/components/PostContent/PostContent.tsx index c2d360b4d..e852da74d 100644 --- a/src/v4/social/components/PostContent/PostContent.tsx +++ b/src/v4/social/components/PostContent/PostContent.tsx @@ -400,7 +400,10 @@ export const PostContent = ({ ) : null} {post.createdAt !== post.editedAt && ( - + (edited) )} diff --git a/src/v4/social/components/ReplyComment/ReplyComment.tsx b/src/v4/social/components/ReplyComment/ReplyComment.tsx index 1e3c850c2..b2e5ad2ac 100644 --- a/src/v4/social/components/ReplyComment/ReplyComment.tsx +++ b/src/v4/social/components/ReplyComment/ReplyComment.tsx @@ -187,7 +187,9 @@ const PostReplyComment = ({ pageId = '*', community, comment }: ReplyCommentProp componentId={componentId} timestamp={comment.createdAt} /> - {comment.createdAt !== comment.editedAt && ' (edited)'} + + {comment.createdAt !== comment.editedAt && ' (edited)'} +
= ({ const { community } = useCommunityInfo(communityId); const { currentUserId, client } = useSDK(); - const { user } = useUser(currentUserId); + const { user } = useUser({ userId: currentUserId }); const isGlobalAdmin = isAdmin(user?.roles); const hasStoryPermission = isGlobalAdmin || checkStoryPermission(client, communityId); const hasStories = stories?.length > 0; diff --git a/src/v4/social/components/StoryTab/StoryTabGlobalFeed.tsx b/src/v4/social/components/StoryTab/StoryTabGlobalFeed.tsx index 6e4d6be36..e055de545 100644 --- a/src/v4/social/components/StoryTab/StoryTabGlobalFeed.tsx +++ b/src/v4/social/components/StoryTab/StoryTabGlobalFeed.tsx @@ -24,7 +24,7 @@ export const StoryTabGlobalFeed = ({ pageId, componentId, }); - const { stories, isLoading, hasMore, loadMoreStories } = useGlobalStoryTargets({ + const { stories, isLoading, hasMore, loadMoreStories, refresh } = useGlobalStoryTargets({ seenState: 'smart' as Amity.StorySeenQuery, limit: STORIES_PER_PAGE, }); @@ -32,6 +32,10 @@ export const StoryTabGlobalFeed = ({ const containerRef = useRef(null); const observerRef = useRef(null); + useEffect(() => { + refresh(); + }, []); + useEffect(() => { if (!containerRef.current) { return; diff --git a/src/v4/social/components/StoryTab/StoryTabItem.module.css b/src/v4/social/components/StoryTab/StoryTabItem.module.css index 17435b850..d19b31be9 100644 --- a/src/v4/social/components/StoryTab/StoryTabItem.module.css +++ b/src/v4/social/components/StoryTab/StoryTabItem.module.css @@ -46,6 +46,8 @@ overflow: hidden; text-overflow: ellipsis; color: var(--asc-color-secondary-default); + display: grid; + grid-template-columns: repeat(2, 1fr); } .errorIcon { @@ -54,3 +56,9 @@ right: 0; cursor: pointer; } + +.lockIcon { + width: 0.875rem; + height: 0.875rem; + fill: currentcolor; +} diff --git a/src/v4/social/components/StoryTab/StoryTabItem.tsx b/src/v4/social/components/StoryTab/StoryTabItem.tsx index 6d134d8d2..9c77c6659 100644 --- a/src/v4/social/components/StoryTab/StoryTabItem.tsx +++ b/src/v4/social/components/StoryTab/StoryTabItem.tsx @@ -9,6 +9,7 @@ import useCommunity from '~/v4/core/hooks/collections/useCommunity'; import { useImage } from '~/v4/core/hooks/useImage'; import styles from './StoryTabItem.module.css'; +import Lock from '~/v4/icons/Lock'; const ErrorIcon = (props: React.SVGProps) => { return ( @@ -102,7 +103,7 @@ export const StoryTabItem: React.FC = ({ data-qa-anchor={`${pageId}/${componentId}/community_name`} className={clsx(styles.displayName)} > - {!community?.isPublic && } + {!community?.isPublic && } {community?.displayName}
diff --git a/src/v4/social/elements/CommunityAvatar/CommunityAvatar.tsx b/src/v4/social/elements/CommunityAvatar/CommunityAvatar.tsx index 6c1015b50..50112e2b3 100644 --- a/src/v4/social/elements/CommunityAvatar/CommunityAvatar.tsx +++ b/src/v4/social/elements/CommunityAvatar/CommunityAvatar.tsx @@ -2,6 +2,7 @@ import React from 'react'; import useImage from '~/core/hooks/useImage'; import { useAmityElement } from '~/v4/core/hooks/uikit'; import styles from './CommunityAvatar.module.css'; +import clsx from 'clsx'; const CommunityAvatarSvg = (props: React.SVGProps) => ( ) => ( export interface CommunityAvatarProps { pageId?: string; + className?: string; componentId?: string; community?: Amity.Community | null; } @@ -31,6 +33,7 @@ export function CommunityAvatar({ pageId = '*', componentId = '*', community, + className, }: CommunityAvatarProps) { const elementId = 'community_avatar'; const { accessibilityId, isExcluded, themeStyles } = useAmityElement({ @@ -47,11 +50,11 @@ export function CommunityAvatar({ return ( diff --git a/src/v4/social/elements/CreateNewPostButton/CreateNewPostButton.tsx b/src/v4/social/elements/CreateNewPostButton/CreateNewPostButton.tsx index ed28d4278..31b25a1e3 100644 --- a/src/v4/social/elements/CreateNewPostButton/CreateNewPostButton.tsx +++ b/src/v4/social/elements/CreateNewPostButton/CreateNewPostButton.tsx @@ -7,7 +7,7 @@ interface CreateNewPostButtonProps { pageId: string; componentId?: string; isValid: boolean; - onSubmit: () => void; + onSubmit?: () => void; } export function CreateNewPostButton({ diff --git a/src/v4/social/elements/PostTextField/PostTextField.tsx b/src/v4/social/elements/PostTextField/PostTextField.tsx index 25ee78ed0..315603c5f 100644 --- a/src/v4/social/elements/PostTextField/PostTextField.tsx +++ b/src/v4/social/elements/PostTextField/PostTextField.tsx @@ -211,6 +211,8 @@ export const PostTextField = ({ {options.map((option, i: number) => { return ( { setHighlightedIndex(i); diff --git a/src/v4/social/elements/ShareStoryButton/ShareStoryButton.module.css b/src/v4/social/elements/ShareStoryButton/ShareStoryButton.module.css index 0992c06ed..1cc8cd5f1 100644 --- a/src/v4/social/elements/ShareStoryButton/ShareStoryButton.module.css +++ b/src/v4/social/elements/ShareStoryButton/ShareStoryButton.module.css @@ -19,3 +19,8 @@ .shareStoryIcon { margin-left: var(--asc-spacing-s1); } + +.shareStoryButton__image { + width: 2rem; + height: 2rem; +} diff --git a/src/v4/social/elements/ShareStoryButton/ShareStoryButton.tsx b/src/v4/social/elements/ShareStoryButton/ShareStoryButton.tsx index 66e4e7e28..9feb99ecf 100644 --- a/src/v4/social/elements/ShareStoryButton/ShareStoryButton.tsx +++ b/src/v4/social/elements/ShareStoryButton/ShareStoryButton.tsx @@ -5,6 +5,7 @@ import { useAmityElement } from '~/v4/core/hooks/uikit'; import styles from './ShareStoryButton.module.css'; import { CommunityAvatar } from '~/v4/social/elements/CommunityAvatar'; +import { Button } from '~/v4/core/natives/Button'; const ArrowRightIcon = (props: React.SVGProps) => { return ( @@ -47,18 +48,22 @@ export const ShareStoryButton = ({ if (isExcluded) return null; return ( - + ); }; diff --git a/src/v4/social/hooks/collections/useGlobalStoryTargets.ts b/src/v4/social/hooks/collections/useGlobalStoryTargets.ts index cb3a4f1e5..513e488b6 100644 --- a/src/v4/social/hooks/collections/useGlobalStoryTargets.ts +++ b/src/v4/social/hooks/collections/useGlobalStoryTargets.ts @@ -4,7 +4,7 @@ import useLiveCollection from '~/v4/core/hooks/useLiveCollection'; export const useGlobalStoryTargets = ( params: Amity.LiveCollectionParams, ) => { - const { items, hasMore, loadMore, isLoading, ...rest } = useLiveCollection({ + const { items, hasMore, loadMore, isLoading, refresh, ...rest } = useLiveCollection({ fetcher: StoryRepository.getGlobalStoryTargets, params, shouldCall: true, @@ -21,6 +21,7 @@ export const useGlobalStoryTargets = ( hasMore, isLoading, loadMoreStories, + refresh, ...rest, }; }; diff --git a/src/v4/social/internal-components/CreatePost/CreatePost.tsx b/src/v4/social/internal-components/CreatePost/CreatePost.tsx index fcb9d1dca..f8f2f79a8 100644 --- a/src/v4/social/internal-components/CreatePost/CreatePost.tsx +++ b/src/v4/social/internal-components/CreatePost/CreatePost.tsx @@ -300,7 +300,6 @@ export function CreatePost({ community, targetType, targetId }: AmityPostCompose 0 || postImages.length > 0 || postVideos.length > 0} />
@@ -349,6 +348,7 @@ export function CreatePost({ community, targetType, targetId }: AmityPostCompose } as React.CSSProperties } className={styles.mentionTextInput_item} + data-qa-anchor={`${pageId}/mention_text_input_options`} />
diff --git a/src/v4/social/internal-components/Lexical/MentionItem.tsx b/src/v4/social/internal-components/Lexical/MentionItem.tsx index 9cd28181b..ec76ba63b 100644 --- a/src/v4/social/internal-components/Lexical/MentionItem.tsx +++ b/src/v4/social/internal-components/Lexical/MentionItem.tsx @@ -33,6 +33,7 @@ export function MentionItem({ key={option.key} tabIndex={-1} data-is-selected={isSelected} + data-qa-ancgor={`${pageId}/${componentId}/mention_item`} className={styles.userMentionItem__item} ref={option.setRefElement} role="option" diff --git a/src/v4/social/internal-components/MentionTextInput/MentionTextInput.tsx b/src/v4/social/internal-components/MentionTextInput/MentionTextInput.tsx index 0cd348702..d5e65f603 100644 --- a/src/v4/social/internal-components/MentionTextInput/MentionTextInput.tsx +++ b/src/v4/social/internal-components/MentionTextInput/MentionTextInput.tsx @@ -231,6 +231,7 @@ function Mention({
{options.map((option, i: number) => ( member.userId === client?.userId); const isMember = member != null; - const { user } = useUser(client?.userId); + const { user } = useUser({ userId: client?.userId }); const isOfficial = community?.isOfficial || false; const isCreator = creator?.userId === user?.userId; diff --git a/src/v4/social/internal-components/StoryViewer/Renderers/Video.tsx b/src/v4/social/internal-components/StoryViewer/Renderers/Video.tsx index b4e2e867d..59c3764ba 100644 --- a/src/v4/social/internal-components/StoryViewer/Renderers/Video.tsx +++ b/src/v4/social/internal-components/StoryViewer/Renderers/Video.tsx @@ -97,7 +97,7 @@ export const renderer: CustomRenderer = ({ const [loaded, setLoaded] = useState(false); const { loader } = config; const { client } = useSDK(); - const { user } = useUser(client?.userId); + const { user } = useUser({ userId: client?.userId }); const vid = useRef(null); const { muted, mute, unmute } = useAudioControl(); @@ -140,6 +140,8 @@ export const renderer: CustomRenderer = ({ const haveStoryPermission = isGlobalAdmin || isModeratorUser || checkStoryPermission(client, community?.communityId); + const [isLoading, setIsLoading] = useState(true); + const videoLoaded = useCallback(() => { messageHandler('UPDATE_VIDEO_DURATION', { // TODO: need to fix video type from TS-SDK @@ -166,6 +168,7 @@ export const renderer: CustomRenderer = ({ vid.current.pause(); action('pause', true); } else { + videoLoaded(); vid.current.play(); action('play', true); } @@ -268,12 +271,19 @@ export const renderer: CustomRenderer = ({ controls={false} onLoadedData={videoLoaded} playsInline - onWaiting={() => action('pause', true)} - onPlaying={() => action('play', true)} + onCanPlay={() => { + setIsLoading(false); + }} + onWaiting={() => { + action('pause', true); + }} + onPlaying={() => { + action('play', true); + }} muted={muted} autoPlay /> - {!loaded && ( + {(!loaded || isLoading) && (
{loader ||
loading...
}
)} void; onDiscardCreateStory: () => void; }) => { - const { page } = useNavigation(); + const { page, onBack } = useNavigation(); const pageId = 'create_story_page'; const { accessibilityId, themeStyles } = useAmityPage({ pageId, @@ -101,7 +101,7 @@ export const PlainDraftStoryPage = ({ if (page.type === PageTypes.DraftPage && page.context.storyType === 'globalFeed') { goToGlobalFeedPage(); } else { - goToCommunityPage(targetId); + onBack(); } if (mediaType?.type === 'image' && targetId) { await StoryRepository.createImageStory( diff --git a/src/v4/social/pages/StoryPage/CommunityFeedStory.tsx b/src/v4/social/pages/StoryPage/CommunityFeedStory.tsx index 1f8f28323..25dd39f97 100644 --- a/src/v4/social/pages/StoryPage/CommunityFeedStory.tsx +++ b/src/v4/social/pages/StoryPage/CommunityFeedStory.tsx @@ -70,7 +70,7 @@ export const CommunityFeedStory = ({ const dragEventTarget = useRef(new EventTarget()); const [isBottomSheetOpen, setIsBottomSheetOpen] = useState(false); - const { stories } = useGetActiveStoriesByTarget({ + const { stories: storiesData } = useGetActiveStoriesByTarget({ targetId: communityId, targetType: 'community', options: { @@ -79,6 +79,22 @@ export const CommunityFeedStory = ({ }, }); + const stories = storiesData.reduce( + (acc: (Amity.Ad | Amity.Story)[], current: Amity.Ad | Amity.Story) => { + const isDuplicate = acc.find((item) => { + if (isStory(item) && isStory(current)) { + return item.storyId === current.storyId; + } + return false; + }); + if (!isDuplicate) { + acc.push(current); + } + return acc; + }, + [], + ); + const communityFeedRenderers = useMemo( () => renderers.map(({ renderer, tester }) => { @@ -115,7 +131,7 @@ export const CommunityFeedStory = ({ const nextStory = () => { if (currentIndex === stories.length - 1) { - onBack(); + onClose(communityId); return; } setCurrentIndex(currentIndex + 1); @@ -214,7 +230,7 @@ export const CommunityFeedStory = ({ const increaseIndex = () => { if (currentIndex === stories.length - 1) { - onBack(); + onClose(communityId); return; } setCurrentIndex((prevIndex) => prevIndex + 1); diff --git a/src/v4/social/pages/StoryPage/GlobalFeedStory.tsx b/src/v4/social/pages/StoryPage/GlobalFeedStory.tsx index e09ac9809..1d02d0091 100644 --- a/src/v4/social/pages/StoryPage/GlobalFeedStory.tsx +++ b/src/v4/social/pages/StoryPage/GlobalFeedStory.tsx @@ -326,6 +326,13 @@ export const GlobalFeedStory: React.FC = ({ if (!stories || stories.length === 0) return null; + const getCurrentIndex = () => { + if (formattedStories[currentIndex]) return currentIndex; + const lastStoryIndex = formattedStories.length - 1; + setCurrentIndex(lastStoryIndex); + return lastStoryIndex; + }; + return (
@@ -368,7 +375,7 @@ export const GlobalFeedStory: React.FC = ({ display: 'none', }} preventDefault - currentIndex={currentIndex} + currentIndex={getCurrentIndex()} stories={formattedStories} renderers={globalFeedRenderers as RendererObject[]} defaultInterval={DEFAULT_IMAGE_DURATION}