diff --git a/.github/workflows/check_do_not_merge.yaml b/.github/workflows/check_do_not_merge.yaml new file mode 100644 index 000000000..0f1d237b4 --- /dev/null +++ b/.github/workflows/check_do_not_merge.yaml @@ -0,0 +1,21 @@ +name: Check do not merge + +on: + pull_request: + types: + - opened + - reopened + - synchronize + - edited + - labeled + - unlabeled + +jobs: + ok-to-merge: + if: contains(github.event.pull_request.labels.*.name, 'DO NOT MERGE') == false + runs-on: ubuntu-latest + steps: + - name: This PR is not labeled with do not merge + run: | + echo "This PR can be merged" + exit 0 diff --git a/.github/workflows/check_release_label.yaml b/.github/workflows/check_release_label.yaml new file mode 100644 index 000000000..e742da83e --- /dev/null +++ b/.github/workflows/check_release_label.yaml @@ -0,0 +1,42 @@ +name: Check release label + +on: + pull_request: + types: + - opened + - reopened + - synchronize + - edited + - labeled + - unlabeled + +jobs: + it-has-a-release-label: + runs-on: ubuntu-latest + steps: + - name: Check for Release label + id: check_release_label + run: | + echo "Debugging: Contents of GITHUB_EVENT_PATH" + cat "$GITHUB_EVENT_PATH" + + echo "Debugging: Extracting labels" + labels=$(jq -r '.pull_request.labels[].name' "$GITHUB_EVENT_PATH") + echo "Extracted labels: $labels" + + echo "Debugging: Checking for Release label" + if echo "$labels" | grep -q "^Release/"; then + echo "Release label found" + echo "has_release_label=true" >> $GITHUB_OUTPUT + else + echo "No Release label found" + echo "has_release_label=false" >> $GITHUB_OUTPUT + fi + + echo "Debugging: Final GITHUB_OUTPUT" + cat $GITHUB_OUTPUT + - name: Fail if PR does not have a release label + if: steps.check_release_label.outputs.has_release_label == 'false' + run: | + echo "This PR must have a release label." + exit 1 diff --git a/CHANGELOG.md b/CHANGELOG.md index f3c2fc57e..c5c348ea7 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.11 (2024-08-16) + ## 4.0.0-beta.10 (2024-07-24) ## 4.0.0-beta.9 (2024-07-12) diff --git a/package.json b/package.json index 8d6a8d06c..e5009886a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@amityco/ui-kit-open-source", - "version": "4.0.0-beta.10", + "version": "4.0.0-beta.11", "engines": { "node": ">=20", "pnpm": "9" diff --git a/src/chat/components/Chat/index.tsx b/src/chat/components/Chat/index.tsx index f3258bab7..917502530 100644 --- a/src/chat/components/Chat/index.tsx +++ b/src/chat/components/Chat/index.tsx @@ -13,8 +13,6 @@ import ChatHeader from '~/chat/components/ChatHeader'; import { ChannelContainer } from './styles'; import { useCustomComponent } from '~/core/providers/CustomComponentsProvider'; -import useChannel from '~/chat/hooks/useChannel'; -import useChannelMembers from '~/chat/hooks/useChannelMembers'; interface ChatProps { channelId: string; @@ -23,23 +21,11 @@ interface ChatProps { } const Chat = ({ channelId, onChatDetailsClick, shouldShowChatDetails }: ChatProps) => { - const channel = useChannel(channelId); useEffect(() => { - async function run() { - if (channel == null) return; - - if (channel.type !== 'conversation') { - await ChannelRepository.joinChannel(channel?.channelId); - } - - await SubChannelRepository.startReading(channel?.channelId); - } - run(); return () => { - if (channel == null) return; - SubChannelRepository.stopReading(channel?.channelId); + SubChannelRepository.stopReading(channelId); }; - }, [channel]); + }, [channelId]); const sendMessage = async (text: string) => { return MessageRepository.createMessage({ diff --git a/src/chat/components/Message/styles.tsx b/src/chat/components/Message/styles.tsx index b5a5dfff7..771e01b0b 100644 --- a/src/chat/components/Message/styles.tsx +++ b/src/chat/components/Message/styles.tsx @@ -7,6 +7,8 @@ import { Close, EllipsisV, Save, TrashIcon } from '~/icons'; export const EditingContainer = styled.div` display: flex; align-items: center; + gap: 10px; + padding: 0 10px; `; export const EditingInput = styled.input` @@ -18,21 +20,19 @@ export const EditingInput = styled.input` border-radius: 4px; `; -export const SaveIcon = styled(Save)<{ icon?: ReactNode }>` - opacity: 0.7; - padding: 0 10px; - cursor: pointer; -`; - -export const DeleteIcon = styled(TrashIcon)` +export const SaveIcon = styled(Save).attrs<{ icon?: ReactNode }>({ + width: 14, + height: 14, +})` opacity: 0.7; - padding: 0 10px; cursor: pointer; `; -export const CloseIcon = styled(Close)<{ icon?: ReactNode }>` +export const CloseIcon = styled(Close).attrs<{ icon?: ReactNode }>({ + width: 14, + height: 14, +})` opacity: 0.7; - padding: 0 10px; cursor: pointer; `; diff --git a/src/chat/components/RecentChat/index.tsx b/src/chat/components/RecentChat/index.tsx index 3621e19a0..c567a3c16 100644 --- a/src/chat/components/RecentChat/index.tsx +++ b/src/chat/components/RecentChat/index.tsx @@ -13,6 +13,7 @@ import { } from './styles'; import { useCustomComponent } from '~/core/providers/CustomComponentsProvider'; import useChannelsCollection from '~/chat/hooks/collections/useChannelsCollection'; +import { ChannelRepository, SubChannelRepository } from '@amityco/ts-sdk'; interface RecentChatProps { onChannelSelect?: (data: { channelId: string; type: string }) => void; @@ -34,6 +35,13 @@ const RecentChat = ({ }); const containerRef = useRef(null); + const onClickChannel = async ({ channelId, type }: { channelId: string; type: string }) => { + if (type !== 'conversation') { + await ChannelRepository.joinChannel(channelId); + } + await SubChannelRepository.startReading(channelId); + }; + return ( @@ -66,6 +74,7 @@ const RecentChat = ({ channelId={channel.channelId} isSelected={selectedChannelId === channel.channelId} onSelect={(data) => { + onClickChannel(data); onChannelSelect?.(data); }} /> diff --git a/src/chat/hooks/useChatInfo.ts b/src/chat/hooks/useChatInfo.ts index 270444724..c241c9c8c 100644 --- a/src/chat/hooks/useChatInfo.ts +++ b/src/chat/hooks/useChatInfo.ts @@ -53,23 +53,33 @@ async function getAvatarUrl({ return null; } -async function getChatAvatar( - channel?: Amity.Channel | null, - otherUser?: { avatarUrl?: string } | null, - currentUser?: { avatarUrl?: string } | null, -) { +async function getChatAvatar({ + channelAvatarFileId, + channelAvatarCustomUrl, + otherUserAvatarUrl, + currentUserAvatarUrl, + isDirectChat, + memberCount = 0, +}: { + channelAvatarFileId?: string; + channelAvatarCustomUrl?: string; + otherUserAvatarUrl?: string; + currentUserAvatarUrl?: string; + isDirectChat?: boolean; + memberCount?: number; +}) { // It is direct chat but only one user - show current user instead - if (channel?.memberCount === MEMBER_COUNT_PER_CASE.ONLY_ME_CHAT) { - return getAvatarUrl({ avatarCustomUrl: currentUser?.avatarUrl }); + if (memberCount === MEMBER_COUNT_PER_CASE.ONLY_ME_CHAT) { + return getAvatarUrl({ avatarCustomUrl: currentUserAvatarUrl }); } - if (channel?.metadata?.isDirectChat && otherUser?.avatarUrl) { - return getAvatarUrl({ avatarCustomUrl: otherUser.avatarUrl }); + if (isDirectChat && otherUserAvatarUrl) { + return getAvatarUrl({ avatarCustomUrl: otherUserAvatarUrl }); } return getAvatarUrl({ - avatarFileId: channel?.avatarFileId, - avatarCustomUrl: channel?.metadata?.avatarCustomUrl, + avatarFileId: channelAvatarFileId, + avatarCustomUrl: channelAvatarCustomUrl, }); } @@ -89,17 +99,27 @@ function useChatInfo({ channel }: { channel: Amity.Channel | null }) { useEffect(() => { async function run() { - setChatAvatar(null); - const url = await getChatAvatar( - channel, - { avatarUrl: otherUser?.avatarCustomUrl || otherUserAvatarUrl }, - { avatarUrl: currentUser?.avatarCustomUrl || currentUserAvatarUrl }, - ); + const url = await getChatAvatar({ + channelAvatarFileId: channel?.avatarFileId, + channelAvatarCustomUrl: channel?.metadata?.avatarCustomUrl, + otherUserAvatarUrl: otherUser?.avatarCustomUrl || otherUserAvatarUrl, + currentUserAvatarUrl: currentUser?.avatarCustomUrl || currentUserAvatarUrl, + isDirectChat: channel?.metadata?.isDirectChat, + memberCount: channel?.memberCount, + }); setChatAvatar(url); } run(); - }, [otherUser?.avatarCustomUrl, channel, currentUserAvatarUrl, currentUser?.avatarCustomUrl]); + }, [ + otherUser?.avatarCustomUrl, + channel?.metadata?.isDirectChat, + channel?.memberCount, + channel?.avatarFileId, + channel?.metadata?.avatarCustomUrl, + currentUserAvatarUrl, + currentUser?.avatarCustomUrl, + ]); const chatName = useMemo(() => { if (channel == null) return; diff --git a/src/core/providers/UiKitProvider/index.tsx b/src/core/providers/UiKitProvider/index.tsx index 7b050bdfd..00bcb24b6 100644 --- a/src/core/providers/UiKitProvider/index.tsx +++ b/src/core/providers/UiKitProvider/index.tsx @@ -36,7 +36,6 @@ interface UiKitProviderProps { http?: string; mqtt?: string; }; - authToken?: string; userId: string; displayName: string; customComponents?: CustomComponentType; @@ -59,13 +58,13 @@ interface UiKitProviderProps { onConnected?: () => void; onDisconnected?: () => void; pageBehavior?: Record; + getAuthToken?: () => Promise; } const UiKitProvider = ({ apiKey, apiRegion, apiEndpoint, - authToken, userId, displayName, customComponents = {}, @@ -76,6 +75,7 @@ const UiKitProvider = ({ actionHandlers, onConnectionStatusChange, onDisconnected, + getAuthToken, }: UiKitProviderProps) => { const queryClient = new QueryClient(); const [isConnected, setIsConnected] = useState(false); @@ -105,20 +105,25 @@ const UiKitProvider = ({ setClient(ascClient); } - await ASCClient.login( - { userId, displayName, authToken }, - { - sessionWillRenewAccessToken(renewal) { - // secure mode - if (authToken) { - renewal.renewWithAuthToken(authToken); - return; - } + let params: Amity.ConnectClientParams = { userId, displayName }; + + if (getAuthToken) { + const authToken = await getAuthToken(); + params = { ...params, authToken }; + } + await ASCClient.login(params, { + sessionWillRenewAccessToken(renewal) { + // secure mode + if (getAuthToken) { + getAuthToken().then((authToken) => { + renewal.renewWithAuthToken(authToken); + }); + } else { renewal.renew(); - }, + } }, - ); + }); setIsConnected(true); if (stateChangeRef.current == null) { diff --git a/src/social/components/post/Creator/styles.tsx b/src/social/components/post/Creator/styles.tsx index a4eeaea01..8385b2dcd 100644 --- a/src/social/components/post/Creator/styles.tsx +++ b/src/social/components/post/Creator/styles.tsx @@ -15,6 +15,7 @@ export const PostCreatorContainer = styled.div` display: flex; background: ${({ theme }) => theme.palette.system.background}; border-radius: 4px; + margin-bottom: 12px; `; export const Footer = styled.div` diff --git a/src/social/components/post/Post/styles.tsx b/src/social/components/post/Post/styles.tsx index f56d302eb..4835bedb5 100644 --- a/src/social/components/post/Post/styles.tsx +++ b/src/social/components/post/Post/styles.tsx @@ -33,6 +33,7 @@ export const PostContainer = styled(PlainPostContainer)` background: ${({ theme }) => theme.palette.system.background}; border: 1px solid #edeef2; border-radius: 4px; + margin-bottom: 12px; `; export const PostHeadContainer = styled.div` diff --git a/src/social/components/post/TextContent/index.tsx b/src/social/components/post/TextContent/index.tsx index 3beab50b7..db62e2756 100644 --- a/src/social/components/post/TextContent/index.tsx +++ b/src/social/components/post/TextContent/index.tsx @@ -1,6 +1,5 @@ -import React, { useState, useMemo } from 'react'; +import React, { useState, useMemo, useEffect, useRef } from 'react'; import { FormattedMessage } from 'react-intl'; -import Truncate from 'react-truncate-markup'; import styled from 'styled-components'; import { processChunks } from '~/core/components/ChunkHighlighter'; @@ -10,11 +9,20 @@ import MentionHighlightTag from '~/core/components/MentionHighlightTag'; import { Mentioned, findChunks } from '~/helpers/utils'; import { useCustomComponent } from '~/core/providers/CustomComponentsProvider'; -export const PostContent = styled.div` +export const PostContent = styled.div<{ isExpanded: boolean; postMaxLines: number }>` overflow-wrap: break-word; color: ${({ theme }) => theme.palette.neutral.main}; white-space: pre-wrap; - ${({ theme }) => theme.typography.body} + ${({ theme }) => theme.typography.body}; + max-height: ${({ isExpanded, postMaxLines }) => + isExpanded ? 'none' : `calc(${postMaxLines} * 1.5em)`}; /* Adjust height based on line count */ + overflow: hidden; + position: relative; + + /* Hide the ellipsis */ + &::after { + content: ''; + } `; export const ReadMoreButton = styled(Button).attrs({ variant: 'secondary' })` @@ -29,53 +37,62 @@ interface TextContentProps { mentionees?: Mentioned[]; } -const TextContent = ({ text, postMaxLines, mentionees }: TextContentProps) => { +const TextContent = ({ text, postMaxLines = 8, mentionees }: TextContentProps) => { const chunks = useMemo( () => processChunks(text || '', findChunks(mentionees)), [mentionees, text], ); + const contentRef = useRef(null); + const [isExpanded, setIsExpanded] = useState(false); + const [isTruncated, setIsTruncated] = useState(false); + + useEffect(() => { + if (contentRef.current) { + const { scrollHeight, clientHeight } = contentRef.current; + setIsTruncated(scrollHeight > clientHeight); + } + }, [text, postMaxLines]); + + const onExpand = () => setIsExpanded(true); + const textContent = text ? ( - - - {chunks.map((chunk) => { - const key = `${text}-${chunk.start}-${chunk.end}`; - const sub = text.substring(chunk.start, chunk.end); - if (chunk.highlight) { - const mentionee = mentionees?.find((m) => m.index === chunk.start); - if (mentionee) { - return ( - - {sub} - - ); - } - return {sub}; + + {chunks.map((chunk) => { + const key = `${text}-${chunk.start}-${chunk.end}`; + const sub = text.substring(chunk.start, chunk.end); + if (chunk.highlight) { + const mentionee = mentionees?.find((m) => m.index === chunk.start); + if (mentionee) { + return ( + + {sub} + + ); } - return {sub}; - })} - + return {sub}; + } + return {sub}; + })} ) : null; - const [isExpanded, setIsExpanded] = useState(false); - const onExpand = () => setIsExpanded(true); - if (!textContent) return null; - if (isExpanded) return textContent; - return ( - + {textContent} + {!isExpanded && isTruncated && ( - } - > - {textContent} - + )} + ); }; diff --git a/src/social/pages/UserFeed/Followers/FollowersList.tsx b/src/social/pages/UserFeed/Followers/FollowersList.tsx index 19109365d..ede472813 100644 --- a/src/social/pages/UserFeed/Followers/FollowersList.tsx +++ b/src/social/pages/UserFeed/Followers/FollowersList.tsx @@ -120,7 +120,7 @@ function useFollowerListItems({ userId }: { userId?: string | null }) { const { followers, isLoading, loadMore, hasMore, loadMoreHasBeenCalled } = useFollowersCollection( { userId, - status: 'all', + status: 'accepted', }, ); diff --git a/src/social/pages/UserFeed/Followers/PendingList.tsx b/src/social/pages/UserFeed/Followers/PendingList.tsx index 2da713f4e..288317db2 100644 --- a/src/social/pages/UserFeed/Followers/PendingList.tsx +++ b/src/social/pages/UserFeed/Followers/PendingList.tsx @@ -90,7 +90,7 @@ const PendingList = ({ userId }: { userId?: string | null }) => { isLoadingItem(item) ? ( ) : ( - + ), )} diff --git a/src/v4/chat/internal-components/LiveChatMessageContent/MessageBubble/index.tsx b/src/v4/chat/internal-components/LiveChatMessageContent/MessageBubble/index.tsx index 524e7758f..7936d6dd4 100644 --- a/src/v4/chat/internal-components/LiveChatMessageContent/MessageBubble/index.tsx +++ b/src/v4/chat/internal-components/LiveChatMessageContent/MessageBubble/index.tsx @@ -2,7 +2,7 @@ import React from 'react'; import styles from './styles.module.css'; import useUser from '~/core/hooks/useUser'; import useMessage from '~/chat/hooks/useMessage'; -import MessageTextWithMention from '../MessageTextWithMention/index'; +import MessageTextWithMention from '~/v4/chat/internal-components/LiveChatMessageContent/MessageTextWithMention'; import { Typography } from '~/v4/core/components'; import useSDK from '~/core/hooks/useSDK'; diff --git a/src/v4/chat/internal-components/LiveChatMessageContent/MessageTextWithMention/index.tsx b/src/v4/chat/internal-components/LiveChatMessageContent/MessageTextWithMention/index.tsx index 4cd103569..90445710a 100644 --- a/src/v4/chat/internal-components/LiveChatMessageContent/MessageTextWithMention/index.tsx +++ b/src/v4/chat/internal-components/LiveChatMessageContent/MessageTextWithMention/index.tsx @@ -1,7 +1,7 @@ import React from 'react'; import styles from './styles.module.css'; import { Typography } from '~/v4/core/components'; -import HyperLinkText from '~/v4/core/components/HyperlinkText/index'; +import HyperLinkText from '~/v4/core/components/HyperlinkText'; interface MessageTextWithMentionProps { message: Amity.Message<'text'>; diff --git a/src/v4/chat/internal-components/LiveChatNotification/LiveChatNotification.tsx b/src/v4/chat/internal-components/LiveChatNotification/LiveChatNotification.tsx index a9174bda4..ff83a4708 100644 --- a/src/v4/chat/internal-components/LiveChatNotification/LiveChatNotification.tsx +++ b/src/v4/chat/internal-components/LiveChatNotification/LiveChatNotification.tsx @@ -1,6 +1,6 @@ import React, { ReactNode } from 'react'; import clsx from 'clsx'; -import { Typography } from '~/v4/core/components/index'; +import { Typography } from '~/v4/core/components'; import { useLiveChatNotificationData } from '~/v4/chat/providers/LiveChatNotificationProvider'; import styles from './LiveChatNotification.module.css'; diff --git a/src/v4/chat/pages/LiveChat/LiveChat.tsx b/src/v4/chat/pages/LiveChat/LiveChat.tsx index e7808d27b..fe5102a07 100644 --- a/src/v4/chat/pages/LiveChat/LiveChat.tsx +++ b/src/v4/chat/pages/LiveChat/LiveChat.tsx @@ -1,7 +1,7 @@ import React, { useRef } from 'react'; import { useChannel } from '~/v4/chat/hooks/useChannel'; -import { ChatHeader } from '~/v4/chat/components/ChatHeader/index'; -import ChatContainer from './ChatContainer/index'; +import { ChatHeader } from '~/v4/chat/components/ChatHeader'; +import ChatContainer from './ChatContainer'; import { LiveChatNotificationProvider } from '~/v4/chat/providers/LiveChatNotificationProvider'; import { useAmityPage } from '~/v4/core/hooks/uikit'; diff --git a/src/v4/core/AmityUIKitManager.ts b/src/v4/core/AmityUIKitManager.ts index 760a506e8..af7c82cbb 100644 --- a/src/v4/core/AmityUIKitManager.ts +++ b/src/v4/core/AmityUIKitManager.ts @@ -58,6 +58,7 @@ export class AmityUIKitManager { * @param userId - The user ID to be used for login. * @param displayName - The display name of the user. * @param sessionHandler - The session handler for access token renewal. + * @param authToken - The authentication token to be used for login. * @param onConnectionStatusChange - The callback function for connection status changes. * @param onConnected - The callback function to be called when connected. * @param onDisconnected - The callback function to be called when disconnected. @@ -66,6 +67,7 @@ export class AmityUIKitManager { userId: string, displayName: string, sessionHandler: SessionHandler, + authToken?: string, onConnectionStatusChange?: (state: Amity.SessionStates) => void, onConnected?: () => void, onDisconnected?: () => void, @@ -78,7 +80,12 @@ export class AmityUIKitManager { AmityUIKitManager.instance.onConnected = onConnected; AmityUIKitManager.instance.onDisconnected = onDisconnected; - await AmityUIKitManager.instance.connectAndLogin(userId, displayName, sessionHandler); + await AmityUIKitManager.instance.connectAndLogin( + userId, + displayName, + sessionHandler, + authToken, + ); } /** @@ -105,9 +112,10 @@ export class AmityUIKitManager { userId: string, displayName: string, sessionHandler: SessionHandler, + authToken?: string, ): Promise { await ASCClient.login( - { userId, displayName }, + { userId, displayName, authToken }, { sessionWillRenewAccessToken: sessionHandler.sessionWillRenewAccessToken.bind(sessionHandler), diff --git a/src/v4/core/components/BottomSheet/BottomSheet.module.css b/src/v4/core/components/BottomSheet/BottomSheet.module.css index 91eb82254..a81aa414e 100644 --- a/src/v4/core/components/BottomSheet/BottomSheet.module.css +++ b/src/v4/core/components/BottomSheet/BottomSheet.module.css @@ -20,7 +20,6 @@ which have higher specificity. .bottomSheet__content { background-color: var(--asc-color-background-default); - padding: var(--asc-spacing-m1); } .bottomSheet__backdrop { diff --git a/src/v4/core/components/Drawer/Drawer.tsx b/src/v4/core/components/Drawer/Drawer.tsx index 1afd98ef3..92bcc51d3 100644 --- a/src/v4/core/components/Drawer/Drawer.tsx +++ b/src/v4/core/components/Drawer/Drawer.tsx @@ -1,6 +1,6 @@ import React from 'react'; import styles from './Drawer.module.css'; -import { useDrawer, useDrawerData } from '../../providers/DrawerProvider'; +import { useDrawer, useDrawerData } from '~/v4/core/providers/DrawerProvider'; import { Drawer } from 'vaul'; export const DrawerContainer = () => { diff --git a/src/v4/core/components/Modal/index.tsx b/src/v4/core/components/Modal/index.tsx index 5bdc39f6c..925f356e9 100644 --- a/src/v4/core/components/Modal/index.tsx +++ b/src/v4/core/components/Modal/index.tsx @@ -2,7 +2,7 @@ import React, { ReactNode, useEffect, useRef } from 'react'; import styles from './styles.module.css'; import clsx from 'clsx'; import Close from '~/v4/icons/Close'; -import { useAmityElement } from '../../hooks/uikit'; +import { useAmityElement } from '~/v4/core/hooks/uikit'; export interface ModalProps { pageId?: string; diff --git a/src/v4/core/components/SocialMentionItem/index.tsx b/src/v4/core/components/SocialMentionItem/index.tsx index 76b8f9778..5a0c7c774 100644 --- a/src/v4/core/components/SocialMentionItem/index.tsx +++ b/src/v4/core/components/SocialMentionItem/index.tsx @@ -7,7 +7,7 @@ import useImage from '~/core/hooks/useImage'; import styles from './styles.module.css'; import { MentionIcon } from '~/icons'; import { FormattedMessage } from 'react-intl'; -import { Typography } from '../index'; +import { Typography } from '~/v4/core/components/Typography'; import { Avatar } from '~/v4/core/components/Avatar'; import User from '~/v4/icons/User'; diff --git a/src/v4/core/hooks/usePaginator.ts b/src/v4/core/hooks/usePaginator.ts index 56765ed18..eef8eba8c 100644 --- a/src/v4/core/hooks/usePaginator.ts +++ b/src/v4/core/hooks/usePaginator.ts @@ -1,7 +1,7 @@ import { useMemo, useState } from 'react'; import useLiveCollection from '~/v4/core/hooks/useLiveCollection'; -import { AdEngine } from '../AdEngine'; -import { useAdSettings, useRecommendAds } from '../providers/AdEngineProvider'; +import { AdEngine } from '~/v4/core/AdEngine'; +import { useAdSettings, useRecommendAds } from '~/v4/core/providers/AdEngineProvider'; import { isNonNullable } from '~/v4/helpers/utils'; const usePaginatorCore = ({ @@ -45,13 +45,23 @@ const usePaginatorCore = ({ if (frequency?.type === 'fixed') { const newItemIds = new Set(newItems.map((item) => getItemId(item))); - const prevItemWithAds = itemWithAds + const prevItemWithAds: Array<[T] | [T, Amity.Ad]> = itemWithAds .map((itemWithAd) => { const itemId = getItemId(itemWithAd[0]); if (!newItemIds.has(itemId)) { return null; } + + const updatedItem = newItems.find((newItem) => getItemId(newItem) === itemId); + + if (updatedItem) { + if (itemWithAd.length === 1) { + return [updatedItem] as [T]; + } + return [updatedItem, itemWithAd[1]] as [T, Amity.Ad]; + } + return itemWithAd; }) .filter(isNonNullable); diff --git a/src/v4/core/hooks/usePostedUserInformation.ts b/src/v4/core/hooks/usePostedUserInformation.ts index 1aab50495..e1abd1e5b 100644 --- a/src/v4/core/hooks/usePostedUserInformation.ts +++ b/src/v4/core/hooks/usePostedUserInformation.ts @@ -1,16 +1,19 @@ import { useMemo } from 'react'; import useCommunityModeratorsCollection from '~/v4/social/hooks/collections/useCommunityModeratorsCollection'; +import useSDK from './useSDK'; export const usePostedUserInformation = ({ post, community, }: { - post: Amity.Post; + post?: Amity.Post; community?: Amity.Community | null; }) => { + const { currentUserId } = useSDK(); + const isCommunityPost = useMemo( - () => post.targetType === 'community' && post.targetId === community?.communityId, - [post.targetType, community?.communityId], + () => post?.targetType === 'community' && post?.targetId === community?.communityId, + [post?.targetType, community?.communityId], ); const { moderators } = useCommunityModeratorsCollection({ @@ -25,7 +28,7 @@ export const usePostedUserInformation = ({ return false; }, [moderators, isCommunityPost, post?.postedUserId]); - const isOwner = post.postedUserId === post?.postedUserId; + const isOwner = post?.postedUserId === currentUserId; return { isCommunityModerator, diff --git a/src/v4/core/natives/Button/Button.module.css b/src/v4/core/natives/Button/Button.module.css index 257690dee..b2f924073 100644 --- a/src/v4/core/natives/Button/Button.module.css +++ b/src/v4/core/natives/Button/Button.module.css @@ -1,4 +1,5 @@ .button { box-sizing: border-box; all: unset; + cursor: pointer; } diff --git a/src/v4/core/providers/AdEngineProvider.tsx b/src/v4/core/providers/AdEngineProvider.tsx index c30fd5f6b..c7cae6549 100644 --- a/src/v4/core/providers/AdEngineProvider.tsx +++ b/src/v4/core/providers/AdEngineProvider.tsx @@ -1,7 +1,7 @@ import React, { useContext, useEffect, useState, createContext } from 'react'; -import { AdEngine } from '../AdEngine'; -import { AdSupplier } from '../AdSupplier'; -import { TimeWindowTracker } from '../TimeWindowTracker'; +import { AdEngine } from '~/v4/core/AdEngine'; +import { AdSupplier } from '~/v4/core/AdSupplier'; +import { TimeWindowTracker } from '~/v4/core/TimeWindowTracker'; export const AdEngineContext = createContext<{ ads: Amity.Ad[]; diff --git a/src/v4/core/providers/AmityUIKitProvider.tsx b/src/v4/core/providers/AmityUIKitProvider.tsx index 883feb88d..4fb254718 100644 --- a/src/v4/core/providers/AmityUIKitProvider.tsx +++ b/src/v4/core/providers/AmityUIKitProvider.tsx @@ -1,6 +1,6 @@ -import '../../../core/providers/UiKitProvider/inter.css'; +import '~/core/providers/UiKitProvider/inter.css'; import './index.css'; -import '../../styles/global.css'; +import '~/v4/styles/global.css'; import React, { useEffect, useMemo, useState } from 'react'; import useUser from '~/core/hooks/useUser'; @@ -27,7 +27,7 @@ import { defaultConfig, Config, CustomizationProvider } from './CustomizationPro import { ThemeProvider } from './ThemeProvider'; import { PageBehavior, PageBehaviorProvider } from './PageBehaviorProvider'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { AmityUIKitManager } from '../AmityUIKitManager'; +import { AmityUIKitManager } from '~/v4/core/AmityUIKitManager'; import { ConfirmProvider } from '~/v4/core/providers/ConfirmProvider'; import { ConfirmProvider as LegacyConfirmProvider } from '~/core/providers/ConfirmProvider'; import { NotificationProvider } from '~/v4/core/providers/NotificationProvider'; @@ -35,7 +35,7 @@ import { DrawerProvider } from '~/v4/core/providers/DrawerProvider'; import { NotificationProvider as LegacyNotificationProvider } from '~/core/providers/NotificationProvider'; import { CustomReactionProvider } from './CustomReactionProvider'; import { AdEngineProvider } from './AdEngineProvider'; -import { AdEngine } from '../AdEngine'; +import { AdEngine } from '~/v4/core/AdEngine'; import { GlobalFeedProvider } from '~/v4/social/providers/GlobalFeedProvider'; export type AmityUIKitConfig = Config; @@ -47,7 +47,6 @@ interface AmityUIKitProviderProps { http?: string; mqtt?: string; }; - authToken?: string; userId: string; displayName: string; postRendererConfig?: any; @@ -68,6 +67,7 @@ interface AmityUIKitProviderProps { onConnectionStatusChange?: (state: Amity.SessionStates) => void; onConnected?: () => void; onDisconnected?: () => void; + getAuthToken?: () => Promise; configs?: AmityUIKitConfig; } @@ -75,7 +75,6 @@ const AmityUIKitProvider: React.FC = ({ apiKey, apiRegion, apiEndpoint, - authToken, userId, displayName, postRendererConfig, @@ -85,6 +84,7 @@ const AmityUIKitProvider: React.FC = ({ pageBehavior, onConnectionStatusChange, onDisconnected, + getAuthToken, configs, }) => { const queryClient = new QueryClient(); @@ -102,6 +102,12 @@ const AmityUIKitProvider: React.FC = ({ useEffect(() => { const setup = async () => { + let authToken; + + if (getAuthToken) { + authToken = await getAuthToken(); + } + try { // Set up the AmityUIKitManager AmityUIKitManager.setup({ apiKey, apiRegion, apiEndpoint }); @@ -115,13 +121,16 @@ const AmityUIKitProvider: React.FC = ({ { sessionWillRenewAccessToken: (renewal) => { // Handle access token renewal - if (authToken) { - renewal.renewWithAuthToken(authToken); + if (getAuthToken) { + getAuthToken().then((newToken) => { + renewal.renewWithAuthToken(newToken); + }); } else { renewal.renew(); } }, }, + authToken, onConnectionStatusChange, onDisconnected, ); @@ -134,7 +143,7 @@ const AmityUIKitProvider: React.FC = ({ }; setup(); - }, [userId, displayName, authToken, onConnectionStatusChange, onDisconnected]); + }, [userId, displayName, onConnectionStatusChange, onDisconnected]); if (!client) return null; @@ -152,33 +161,34 @@ const AmityUIKitProvider: React.FC = ({ - - - - - - - - + + + + + + + + {children} - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/src/v4/core/providers/NavigationProvider.tsx b/src/v4/core/providers/NavigationProvider.tsx index 633d5cdc5..3dbe45f54 100644 --- a/src/v4/core/providers/NavigationProvider.tsx +++ b/src/v4/core/providers/NavigationProvider.tsx @@ -1,10 +1,11 @@ import React, { createContext, useCallback, useContext, useState, useMemo, ReactNode } from 'react'; import { AmityStoryMediaType } from '~/v4/social/pages/DraftsPage/DraftsPage'; import { Mode } from '~/v4/social/pages/PostComposerPage/PostComposerPage'; +import { NavigationContext as NavigationContextV3 } from '~/social/providers/NavigationProvider'; export enum PageTypes { Explore = 'explore', - NewsFeed = 'newsFeed', + NewsFeed = 'newsfeed', CommunityFeed = 'communityFeed', CommunityEdit = 'communityEdit', Category = 'category', @@ -119,12 +120,12 @@ type ContextValue = { goToMyCommunitiesSearchPage: () => void; goToSelectPostTargetPage: () => void; goToStoryTargetSelectionPage: () => void; - goToDraftStoryPage: (context: { - targetId: string; - targetType: string; - mediaType: AmityStoryMediaType; - storyType: 'communityFeed' | 'globalFeed'; - }) => void; + goToDraftStoryPage: ( + targetId: string, + targetType: string, + mediaType: AmityStoryMediaType, + storyType: 'communityFeed' | 'globalFeed', + ) => void; goToViewStoryPage: (context: { targetId: string; targetType: Amity.StoryTargetType; @@ -141,11 +142,14 @@ type ContextValue = { | undefined, ) => void; goToPostComposerPage: ( - mode: Mode, - targetId: string | null, - targetType: 'community' | 'user', - community?: Amity.Community, - post?: Amity.Post, + context: + | { + mode: Mode.CREATE; + targetId: string | null; + targetType: 'community' | 'user'; + community?: Amity.Community; + } + | { mode: Mode.EDIT; post: Amity.Post }, ) => void; goToStoryCreationPage: (context: { targetId: string; @@ -154,6 +158,12 @@ type ContextValue = { storyType: 'communityFeed' | 'globalFeed'; }) => void; goToSocialHomePage: () => void; + //V3 functions + onClickStory: ( + storyId: string, + storyType: 'communityFeed' | 'globalFeed', + targetId?: string[], + ) => void; }; let defaultValue: ContextValue = { @@ -173,28 +183,28 @@ let defaultValue: ContextValue = { targetType: Amity.StoryTargetType; storyType: 'communityFeed' | 'globalFeed'; }) => {}, - goToDraftStoryPage: (context: { - targetId: string; - targetType: string; - mediaType: AmityStoryMediaType; - storyType: 'communityFeed' | 'globalFeed'; - }) => {}, + goToDraftStoryPage: ( + targetId: string, + targetType: string, + mediaType: AmityStoryMediaType, + storyType: 'communityFeed' | 'globalFeed', + ) => {}, goToCommunityProfilePage: (communityId: string) => {}, goToSocialGlobalSearchPage: (tab?: string) => {}, goToSelectPostTargetPage: () => {}, goToStoryTargetSelectionPage: () => {}, - goToPostComposerPage: ( - mode: Mode, - targetId: string | null, - targetType: 'community' | 'user', - community?: Amity.Community, - post?: Amity.Post, - ) => {}, + goToPostComposerPage: () => {}, goToStoryCreationPage: () => {}, goToSocialHomePage: () => {}, goToMyCommunitiesSearchPage: () => {}, setNavigationBlocker: () => {}, onBack: () => {}, + //V3 functions + onClickStory: ( + storyId: string, + storyType: 'communityFeed' | 'globalFeed', + targetId?: string[], + ) => {}, }; if (process.env.NODE_ENV !== 'production') { @@ -225,18 +235,16 @@ if (process.env.NODE_ENV !== 'production') { goToSelectPostTargetPage: () => console.log('NavigationContext goToTargetPage()'), goToStoryTargetSelectionPage: () => console.log('NavigationContext goToStoryTargetSelectionPage()'), - goToDraftStoryPage: ({ targetId, targetType, mediaType, storyType }) => - console.log( - `NavigationContext goToDraftStoryPage(${targetId}, ${targetType}, ${mediaType}), ${storyType})`, - ), - goToPostComposerPage: (mode, targetId, targetType, community, post) => - console.log( - `NavigationContext goToPostComposerPage(${mode} ${targetId}) ${targetType} ${community} ${post}`, - ), + goToDraftStoryPage: (data) => console.log(`NavigationContext goToDraftStoryPage()`), + goToPostComposerPage: () => console.log(`NavigationContext goToPostComposerPage()`), goToStoryCreationPage: () => console.log('NavigationContext goToStoryCreationPage()'), goToSocialHomePage: () => console.log('NavigationContext goToSocialHomePage()'), goToMyCommunitiesSearchPage: () => console.log('NavigationContext goToMyCommunitiesSearchPage()'), + + //V3 functions + onClickStory: (storyId, storyType, targetIds) => + console.log(`NavigationContext onClickStory(${storyId}, ${storyType}, ${targetIds})`), }; } @@ -253,7 +261,16 @@ interface NavigationProviderProps { onCancel: () => void; }) => void; children: React.ReactNode; - onChangePage?: (data: { type: string; [x: string]: string | boolean }) => void; + onChangePage?: ( + data: + | { type: string; [x: string]: string | boolean } + | { + type: string; + context: { + [x: string]: string | boolean; + }; + }, + ) => void; onClickCategory?: (categoryId: string) => void; onClickCommunity?: (communityId: string) => void; onClickUser?: (userId: string) => void; @@ -262,17 +279,23 @@ interface NavigationProviderProps { storyType: 'communityFeed' | 'globalFeed'; targetType: Amity.StoryTargetType; }) => void; - goToDraftStoryPage?: (context: { - targetId: string; - targetType: string; - mediaType: AmityStoryMediaType; - storyType: 'communityFeed' | 'globalFeed'; - }) => void; + goToDraftStoryPage?: ( + targetId: string, + targetType: string, + mediaType: AmityStoryMediaType, + storyType: 'communityFeed' | 'globalFeed', + ) => void; onCommunityCreated?: (communityId: string) => void; onEditCommunity?: (communityId: string, options?: { tab?: string }) => void; onEditUser?: (userId: string) => void; onMessageUser?: (userId: string) => void; onBack?: () => void; + //V3 functions + onClickStory?: ( + storyId: string, + storyType: 'communityFeed' | 'globalFeed', + targetId?: string[], + ) => void; } export default function NavigationProvider({ @@ -313,7 +336,16 @@ export default function NavigationProvider({ }; const onChangePage = onChangePageProp - ? async (data: { type: string; [x: string]: string | boolean }) => { + ? async ( + data: + | { type: string; [x: string]: string | boolean } + | { + type: string; + context: { + [x: string]: string | boolean; + }; + }, + ) => { onChangePageProp(data); } : null; @@ -329,7 +361,9 @@ export default function NavigationProvider({ (communityId) => { const next = { type: PageTypes.CommunityFeed, - communityId, + context: { + communityId, + }, }; if (onChangePage) return onChangePage(next); @@ -337,7 +371,7 @@ export default function NavigationProvider({ pushPage(next); }, - [onChangePage, onClickCommunity, pushPage], + [onClickCommunity, pushPage], ); const handleCommunityCreated = useCallback( @@ -375,7 +409,9 @@ export default function NavigationProvider({ (userId, pageType) => { const next = { type: pageType ?? PageTypes.UserFeed, - userId, + context: { + userId, + }, }; if (onChangePage) return onChangePage(next); @@ -390,7 +426,9 @@ export default function NavigationProvider({ (userId) => { const next = { type: PageTypes.UserEdit, - userId, + context: { + userId, + }, }; if (onChangePage) return onChangePage(next); @@ -405,8 +443,10 @@ export default function NavigationProvider({ (communityId, tab) => { const next = { type: PageTypes.CommunityEdit, - communityId, - tab, + context: { + communityId, + tab, + }, }; if (onChangePage) return onChangePage(next); @@ -484,7 +524,7 @@ export default function NavigationProvider({ const goToCommunityProfilePage = useCallback( (communityId) => { const next = { - type: PageTypes.CommunityProfilePage, + type: PageTypes.CommunityFeed, context: { communityId, }, @@ -540,7 +580,7 @@ export default function NavigationProvider({ ); const goToDraftStoryPage = useCallback( - ({ targetId, targetType, mediaType, storyType }) => { + (targetId, targetType, mediaType, storyType) => { const next = { type: PageTypes.DraftPage, context: { @@ -565,16 +605,19 @@ export default function NavigationProvider({ }, [onChangePage, pushPage]); const goToPostComposerPage = useCallback( - (mode, targetId, targetType, community, post) => { + ( + context: + | { + mode: Mode.CREATE; + targetId: string | null; + targetType: 'community' | 'user'; + community?: Amity.Community; + } + | { mode: Mode.EDIT; post: Amity.Post }, + ) => { const next = { type: PageTypes.PostComposerPage, - context: { - mode, - targetId, - targetType, - community, - post, - }, + context, }; pushPage(next); @@ -591,6 +634,24 @@ export default function NavigationProvider({ pushPage(next); }, [onChangePage, pushPage]); + const handleClickStory = useCallback( + (targetId, storyType, targetIds) => { + const next = { + type: PageTypes.ViewStoryPage, + context: { + targetId, + storyType, + targetIds, + }, + }; + + if (onChangePage) return onChangePage(next); + + pushPage(next); + }, + [onChangePage, pushPage], + ); + return ( - {children} + + {children} + ); } diff --git a/src/v4/core/providers/PageBehaviorProvider.tsx b/src/v4/core/providers/PageBehaviorProvider.tsx index f0fdf5184..a8a3f1f81 100644 --- a/src/v4/core/providers/PageBehaviorProvider.tsx +++ b/src/v4/core/providers/PageBehaviorProvider.tsx @@ -25,6 +25,7 @@ export interface PageBehavior { AmityPostContentComponentBehavior?: { goToCommunityProfilePage?: (context: { communityId: string }) => void; goToUserProfilePage?: (context: { userId: string }) => void; + goToPostComposerPage?: (context: { mode: Mode.EDIT; post: Amity.Post }) => void; }; AmitySocialGlobalSearchPageBehavior?: Record; AmityCommunitySearchResultComponentBehavior?: { @@ -36,11 +37,10 @@ export interface PageBehavior { }; AmityPostTargetSelectionPage?: { goToPostComposerPage?: (context: { - mode: Mode.CREATE | Mode.EDIT; + mode: Mode.CREATE; targetId: string | null; targetType: 'community' | 'user'; community?: Amity.Community; - post?: Amity.Post; }) => void; }; AmityStoryTargetSelectionPage?: { @@ -145,6 +145,12 @@ export const PageBehaviorProvider: React.FC = ({ } goToUserProfilePage(context.userId); }, + goToPostComposerPage: (context: { mode: Mode.EDIT; post: Amity.Post }) => { + if (pageBehavior?.AmityPostContentComponentBehavior?.goToPostComposerPage) { + return pageBehavior.AmityPostContentComponentBehavior.goToPostComposerPage(context); + } + goToPostComposerPage(context); + }, }, AmitySocialGlobalSearchPageBehavior: {}, @@ -174,22 +180,15 @@ export const PageBehaviorProvider: React.FC = ({ }, AmityPostTargetSelectionPage: { goToPostComposerPage: (context: { - mode: Mode.CREATE | Mode.EDIT; + mode: Mode.CREATE; targetId: string | null; targetType: 'community' | 'user'; community?: Amity.Community; - post?: Amity.Post; }) => { if (pageBehavior?.AmityPostTargetSelectionPage?.goToPostComposerPage) { return pageBehavior.AmityPostTargetSelectionPage.goToPostComposerPage(context); } - goToPostComposerPage( - context.mode, - context.targetId, - context.targetType, - context.community, - context.post, - ); + goToPostComposerPage(context); }, }, AmityStoryTargetSelectionPage: { diff --git a/src/v4/helpers/utils.ts b/src/v4/helpers/utils.ts index b7b69ff93..a0eea90c0 100644 --- a/src/v4/helpers/utils.ts +++ b/src/v4/helpers/utils.ts @@ -210,7 +210,6 @@ const SUPPORTED_URL_PROTOCOLS = new Set(['http:', 'https:', 'mailto:', 'sms:', ' export function sanitizeUrl(url: string): string { try { const parsedUrl = new URL(url); - // eslint-disable-next-line no-script-url if (!SUPPORTED_URL_PROTOCOLS.has(parsedUrl.protocol)) { return 'about:blank'; } diff --git a/src/v4/social/components/CommentEdition/CommentEdition.tsx b/src/v4/social/components/CommentEdition/CommentEdition.tsx index f402b04f0..bc5f0303d 100644 --- a/src/v4/social/components/CommentEdition/CommentEdition.tsx +++ b/src/v4/social/components/CommentEdition/CommentEdition.tsx @@ -5,9 +5,9 @@ import { ButtonContainer, CommentEditContainer, CommentEditTextarea } from './st import { QueryMentioneesFnType } from '~/v4/chat/hooks/useMention'; import { useTheme } from 'styled-components'; -import { SaveButton } from '../../elements'; +import { SaveButton } from '~/v4/social/elements'; import { useCustomization } from '~/v4/core/providers/CustomizationProvider'; -import { EditCancelButton } from '../../elements/EditCancelButton/EditCancelButton'; +import { EditCancelButton } from '~/v4/social/elements/EditCancelButton/EditCancelButton'; interface CommentEditionProps { pageId?: '*'; diff --git a/src/v4/social/components/CommentOptions/CommentOptions.module.css b/src/v4/social/components/CommentOptions/CommentOptions.module.css index 4f60dd750..c1f20185a 100644 --- a/src/v4/social/components/CommentOptions/CommentOptions.module.css +++ b/src/v4/social/components/CommentOptions/CommentOptions.module.css @@ -1,7 +1,7 @@ .commentOptions__actionButton { display: flex; gap: 0.75rem; - padding: 1rem 0; + padding: 1rem 1.25rem; align-items: center; cursor: pointer; } diff --git a/src/v4/social/components/CommentOptions/CommentOptions.tsx b/src/v4/social/components/CommentOptions/CommentOptions.tsx index e5cb95c11..fa1f62cb3 100644 --- a/src/v4/social/components/CommentOptions/CommentOptions.tsx +++ b/src/v4/social/components/CommentOptions/CommentOptions.tsx @@ -3,9 +3,9 @@ import { useCommentFlaggedByMe } from '~/v4/social/hooks/useCommentFlaggedByMe'; import { useNotifications } from '~/v4/core/providers/NotificationProvider'; import useCommentPermission from '~/social/hooks/useCommentPermission'; import useSDK from '~/v4/core/hooks/useSDK'; -import { Typography } from '~/v4/core/components/index'; +import { Typography } from '~/v4/core/components'; import { isNonNullable } from '~/v4/helpers/utils'; -import { FlagIcon, PenIcon, TrashIcon } from '../../icons/index'; +import { FlagIcon, PenIcon, TrashIcon } from '~/v4/social/icons'; import styles from './CommentOptions.module.css'; interface CommentOptionsProps { diff --git a/src/v4/social/components/CommentTray/CommentTray.module.css b/src/v4/social/components/CommentTray/CommentTray.module.css index 407b12b69..b91770422 100644 --- a/src/v4/social/components/CommentTray/CommentTray.module.css +++ b/src/v4/social/components/CommentTray/CommentTray.module.css @@ -55,6 +55,7 @@ .commentListContainer { overflow-y: auto; flex-grow: 1; + padding: var(--asc-spacing-m1); } .mobileSheetComposeBarContainer { diff --git a/src/v4/social/components/CommentTray/CommentTray.tsx b/src/v4/social/components/CommentTray/CommentTray.tsx index e4d393220..bfde921ad 100644 --- a/src/v4/social/components/CommentTray/CommentTray.tsx +++ b/src/v4/social/components/CommentTray/CommentTray.tsx @@ -1,14 +1,13 @@ import React, { useState } from 'react'; import { useAmityComponent } from '~/v4/core/hooks/uikit'; -import { CommentList } from '~/v4/social/internal-components/CommentList'; -import { StoryCommentComposeBar } from '~/v4/social/internal-components/StoryCommentComposeBar'; -import styles from './CommentTray.module.css'; +import { CommentComposer } from '~/v4/social/components/CommentComposer'; +import { CommentList } from '~/v4/social/components/CommentList'; -const REPLIES_PER_PAGE = 5; +import styles from './CommentTray.module.css'; interface CommentTrayProps { referenceType: Amity.CommentReferenceType; - referenceId?: string; + referenceId: string; community: Amity.Community; shouldAllowInteraction: boolean; shouldAllowCreation?: boolean; @@ -29,16 +28,13 @@ export const CommentTray = ({ componentId, }); - const [isReplying, setIsReplying] = useState(false); const [replyTo, setReplyTo] = useState(null); const onClickReply = (comment: Amity.Comment) => { - setIsReplying(true); setReplyTo(comment); }; const onCancelReply = () => { - setIsReplying(false); setReplyTo(null); }; @@ -50,27 +46,21 @@ export const CommentTray = ({ >
-
-
-
+ ); }; diff --git a/src/v4/social/components/CommunitySearchResult/CommunityItem.tsx b/src/v4/social/components/CommunitySearchResult/CommunityItem.tsx index 420ccf68a..c54212adb 100644 --- a/src/v4/social/components/CommunitySearchResult/CommunityItem.tsx +++ b/src/v4/social/components/CommunitySearchResult/CommunityItem.tsx @@ -7,6 +7,8 @@ import { CommunityPrivateBadge } from '~/v4/social/elements/CommunityPrivateBadg import { CommunityCategoryName } from '~/v4/social/elements/CommunityCategoryName'; import { CommunityMembersCount } from '~/v4/social/elements/CommunityMembersCount'; import styles from './CommunityItem.module.css'; +import { Button } from '~/v4/core/natives/Button'; +import { useNavigation } from '~/v4/core/providers/NavigationProvider'; const CommunityCategories = ({ community, @@ -52,8 +54,15 @@ export const CommunityItem = ({ pageId: string; componentId: string; }) => { + const { onClickCommunity } = useNavigation(); return ( -
+
- + ); }; diff --git a/src/v4/social/components/DetailedMediaAttachment/DetailedMediaAttachment.module.css b/src/v4/social/components/DetailedMediaAttachment/DetailedMediaAttachment.module.css index 11d9e5107..a93c9f236 100644 --- a/src/v4/social/components/DetailedMediaAttachment/DetailedMediaAttachment.module.css +++ b/src/v4/social/components/DetailedMediaAttachment/DetailedMediaAttachment.module.css @@ -7,6 +7,9 @@ box-shadow: var(--asc-box-shadow-04); padding-bottom: 2rem; padding-top: 0.75rem; + margin-top: -1rem; + position: absolute; + bottom: -0.9rem; } .detailedMediaAttachment__swipeDown { diff --git a/src/v4/social/components/DetailedMediaAttachment/DetailedMediaAttachment.tsx b/src/v4/social/components/DetailedMediaAttachment/DetailedMediaAttachment.tsx index 9c0b66042..4db09e0f9 100644 --- a/src/v4/social/components/DetailedMediaAttachment/DetailedMediaAttachment.tsx +++ b/src/v4/social/components/DetailedMediaAttachment/DetailedMediaAttachment.tsx @@ -4,32 +4,23 @@ import styles from './DetailedMediaAttachment.module.css'; import { CameraButton } from '~/v4/social/elements/CameraButton'; import { ImageButton } from '~/v4/social/elements/ImageButton/ImageButton'; import { VideoButton } from '~/v4/social/elements/VideoButton/VideoButton'; -import { FileButton } from '~/v4/social/elements/FileButton'; interface DetailedMediaAttachmentProps { pageId: string; - uploadLoading?: boolean; - onChangeImages?: (files: File[]) => void; - onChangeVideos?: (files: File[]) => void; - onChangeThumbnail?: ( - thumbnail: { file: File; videoUrl: string; thumbnail: string | undefined }[], - ) => void; isVisibleCamera: boolean; isVisibleImage: boolean; isVisibleVideo: boolean; - videoThumbnail?: { file: File; videoUrl: string; thumbnail: string | undefined }[]; + onVideoFileChange?: (files: File[]) => void; + onImageFileChange?: (files: File[]) => void; } export function DetailedMediaAttachment({ pageId, - uploadLoading, - onChangeImages, - onChangeVideos, - onChangeThumbnail, isVisibleCamera, isVisibleImage, isVisibleVideo, - videoThumbnail, + onVideoFileChange, + onImageFileChange, }: DetailedMediaAttachmentProps) { const componentId = 'detailed_media_attachment'; const { themeStyles, accessibilityId, isExcluded } = useAmityComponent({ pageId, componentId }); @@ -47,25 +38,25 @@ export function DetailedMediaAttachment({ )} {isVisibleImage && ( - + )} {isVisibleVideo && ( )} diff --git a/src/v4/social/components/GlobalFeed/GlobalFeed.module.css b/src/v4/social/components/GlobalFeed/GlobalFeed.module.css index 70cefdc60..e5b6c7677 100644 --- a/src/v4/social/components/GlobalFeed/GlobalFeed.module.css +++ b/src/v4/social/components/GlobalFeed/GlobalFeed.module.css @@ -5,6 +5,7 @@ .global_feed__postContainer { padding: 0.25rem 1rem 0.75rem; + width: 94%; } .global_feed__postSkeletonContainer { diff --git a/src/v4/social/components/GlobalFeed/GlobalFeed.tsx b/src/v4/social/components/GlobalFeed/GlobalFeed.tsx index f3518f6fb..2e15cc94a 100644 --- a/src/v4/social/components/GlobalFeed/GlobalFeed.tsx +++ b/src/v4/social/components/GlobalFeed/GlobalFeed.tsx @@ -1,5 +1,5 @@ import React, { useRef } from 'react'; -import { PostContent, PostContentSkeleton } from '../PostContent'; +import { PostContent, PostContentSkeleton } from '~/v4/social/components/PostContent'; import { EmptyNewsfeed } from '~/v4/social/components/EmptyNewsFeed/EmptyNewsFeed'; import useIntersectionObserver from '~/v4/core/hooks/useIntersectionObserver'; import { usePageBehavior } from '~/v4/core/providers/PageBehaviorProvider'; @@ -7,6 +7,7 @@ import { usePageBehavior } from '~/v4/core/providers/PageBehaviorProvider'; import styles from './GlobalFeed.module.css'; import { useAmityComponent } from '~/v4/core/hooks/uikit'; import { PostAd } from '~/v4/social/internal-components/PostAd/PostAd'; +import { Button } from '~/v4/core/natives/Button'; interface GlobalFeedProps { pageId?: string; @@ -68,7 +69,12 @@ export const GlobalFeed = ({ {isAmityAd(item) ? ( ) : ( -
+
+ )} ))} diff --git a/src/v4/social/components/HyperLinkConfig/HyperLinkConfig.tsx b/src/v4/social/components/HyperLinkConfig/HyperLinkConfig.tsx index ee6beb090..a6165d4d2 100644 --- a/src/v4/social/components/HyperLinkConfig/HyperLinkConfig.tsx +++ b/src/v4/social/components/HyperLinkConfig/HyperLinkConfig.tsx @@ -90,11 +90,14 @@ export const HyperLinkConfig = ({ customText: z .string() .optional() - .refine(async (value) => { - if (!value) return true; - const hasBlockedWord = await client?.validateTexts([value]).catch(() => false); - return hasBlockedWord; - }, formatMessage({ id: 'storyCreation.hyperlink.validation.error.blocked' })), + .refine( + async (value) => { + if (!value) return true; + const hasBlockedWord = await client?.validateTexts([value]).catch(() => false); + return hasBlockedWord; + }, + formatMessage({ id: 'storyCreation.hyperlink.validation.error.blocked' }), + ), }); type HyperLinkFormInputs = z.infer; diff --git a/src/v4/social/components/MediaAttachment/MediaAttachment.module.css b/src/v4/social/components/MediaAttachment/MediaAttachment.module.css index 074bf56b4..a10cdf8c8 100644 --- a/src/v4/social/components/MediaAttachment/MediaAttachment.module.css +++ b/src/v4/social/components/MediaAttachment/MediaAttachment.module.css @@ -8,6 +8,9 @@ border-top-left-radius: 1.25rem; border-top-right-radius: 1.25rem; box-shadow: var(--asc-box-shadow-04); + margin-top: 0.75rem; + position: absolute; + bottom: -0.4rem; } .mediaAttachment__swipeDown { diff --git a/src/v4/social/components/MediaAttachment/MediaAttachment.tsx b/src/v4/social/components/MediaAttachment/MediaAttachment.tsx index 7c692f2d8..396306d1b 100644 --- a/src/v4/social/components/MediaAttachment/MediaAttachment.tsx +++ b/src/v4/social/components/MediaAttachment/MediaAttachment.tsx @@ -9,27 +9,20 @@ import clsx from 'clsx'; interface MediaAttachmentProps { pageId: string; uploadLoading?: boolean; - onChangeImages?: (files: File[]) => void; - onChangeVideos?: (files: File[]) => void; - onChangeThumbnail?: ( - thumbnail: { file: File; videoUrl: string; thumbnail: string | undefined }[], - ) => void; isVisibleCamera: boolean; isVisibleImage: boolean; isVisibleVideo: boolean; - videoThumbnail?: { file: File; videoUrl: string; thumbnail: string | undefined }[]; + onVideoFileChange?: (files: File[]) => void; + onImageFileChange?: (files: File[]) => void; } export function MediaAttachment({ pageId, - uploadLoading, - onChangeImages, - onChangeVideos, - onChangeThumbnail, isVisibleCamera, isVisibleImage, isVisibleVideo, - videoThumbnail, + onVideoFileChange, + onImageFileChange, }: MediaAttachmentProps) { const componentId = 'media_attachment'; const { themeStyles, accessibilityId, isExcluded } = useAmityComponent({ pageId, componentId }); @@ -50,25 +43,25 @@ export function MediaAttachment({ )} {isVisibleImage && ( - + )} {isVisibleVideo && ( )} diff --git a/src/v4/social/components/MyCommunities/MyCommunities.tsx b/src/v4/social/components/MyCommunities/MyCommunities.tsx index 093ef0e0d..d5338451c 100644 --- a/src/v4/social/components/MyCommunities/MyCommunities.tsx +++ b/src/v4/social/components/MyCommunities/MyCommunities.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { CommunitySearchResult } from '~/v4/social/components/CommunitySearchResult/'; -import useCommunitiesCollection from '~/v4/core/hooks/collections/useCommunitiesCollection'; +import useCommunitiesCollection from '~/v4/social/hooks/collections/useCommunitiesCollection'; import { useAmityComponent } from '~/v4/core/hooks/uikit'; import styles from './MyCommunities.module.css'; @@ -11,14 +11,13 @@ interface MyCommunitiesProps { export const MyCommunities = ({ pageId = '*' }: MyCommunitiesProps) => { const componentId = 'my_communities'; - const { accessibilityId, config, defaultConfig, isExcluded, uiReference, themeStyles } = - useAmityComponent({ - pageId, - componentId, - }); + const { themeStyles } = useAmityComponent({ + pageId, + componentId, + }); - const { communities, isLoading, error, hasMore, loadMore } = useCommunitiesCollection({ - membership: 'member', + const { communities, hasMore, loadMore, isLoading } = useCommunitiesCollection({ + queryParams: { sortBy: 'displayName', limit: 20, membership: 'member' }, }); return ( diff --git a/src/v4/social/components/Newsfeed/Newsfeed.tsx b/src/v4/social/components/Newsfeed/Newsfeed.tsx index eb179a4d0..741aa2244 100644 --- a/src/v4/social/components/Newsfeed/Newsfeed.tsx +++ b/src/v4/social/components/Newsfeed/Newsfeed.tsx @@ -5,7 +5,7 @@ import { GlobalFeed } from '~/v4/social/components/GlobalFeed'; import styles from './Newsfeed.module.css'; import { useAmityComponent } from '~/v4/core/hooks/uikit'; -import { useGlobalFeedContext } from '../../providers/GlobalFeedProvider'; +import { useGlobalFeedContext } from '~/v4/social/providers/GlobalFeedProvider'; const Spinner = (props: React.SVGProps) => { return ( diff --git a/src/v4/social/components/PostContent/ImageContent/ImageContent.tsx b/src/v4/social/components/PostContent/ImageContent/ImageContent.tsx index 50aeece54..34e67c542 100644 --- a/src/v4/social/components/PostContent/ImageContent/ImageContent.tsx +++ b/src/v4/social/components/PostContent/ImageContent/ImageContent.tsx @@ -2,7 +2,7 @@ import React, { useMemo } from 'react'; import { useImage } from '~/v4/core/hooks/useImage'; import { Typography } from '~/v4/core/components'; -import { useAmityElement } from '~/v4/core/hooks/uikit/index'; +import { useAmityElement } from '~/v4/core/hooks/uikit'; import styles from './ImageContent.module.css'; import usePost from '~/v4/core/hooks/objects/usePost'; import { Button } from '~/v4/core/natives/Button'; diff --git a/src/v4/social/components/PostContent/LinkPreview/LinkPreview.tsx b/src/v4/social/components/PostContent/LinkPreview/LinkPreview.tsx index ff2ecbaef..46bd6f219 100644 --- a/src/v4/social/components/PostContent/LinkPreview/LinkPreview.tsx +++ b/src/v4/social/components/PostContent/LinkPreview/LinkPreview.tsx @@ -6,6 +6,7 @@ import { useQuery } from '@tanstack/react-query'; import useSDK from '~/v4/core/hooks/useSDK'; import { LinkPreviewSkeleton } from './LinkPreviewSkeleton'; import styles from './LinkPreview.module.css'; +import { Button } from '~/v4/core/natives/Button'; const UnableToPreviewSvg = (props: React.SVGProps) => ( +
{urlObject.hostname}
- + ); } return ( -
+