diff --git a/package.json b/package.json
index 3ea4d4c07..16477d6a1 100644
--- a/package.json
+++ b/package.json
@@ -132,7 +132,7 @@
"react-hook-form": "^7.49.2",
"react-infinite-scroll-component": "^6.1.0",
"react-insta-stories": "^2.6.2",
- "react-intl": "^6.5.5",
+ "react-intl": "^6.8.7",
"react-loading-skeleton": "^3.3.1",
"react-mentions": "^4.4.10",
"react-modal-sheet": "^2.2.0",
diff --git a/src/core/components/Button/styles.tsx b/src/core/components/Button/styles.tsx
index 0c83aec57..082b08c9a 100644
--- a/src/core/components/Button/styles.tsx
+++ b/src/core/components/Button/styles.tsx
@@ -19,7 +19,9 @@ const commonButtonStyles = ({ theme }: { theme: DefaultTheme }) => css<{ fullWid
}
`;
-export const DefaultButton = styled.button<{ fullWidth?: boolean }>`
+export const DefaultButton = styled.button.withConfig({
+ shouldForwardProp: (prop) => prop !== 'fullWidth',
+})<{ fullWidth?: boolean }>`
${commonButtonStyles};
background-color: #fff;
border: 1px solid #e3e4e8;
@@ -32,7 +34,9 @@ export const DefaultButton = styled.button<{ fullWidth?: boolean }>`
}
`;
-export const PrimaryButton = styled.button<{ fullWidth?: boolean }>`
+export const PrimaryButton = styled.button.withConfig({
+ shouldForwardProp: (prop) => prop !== 'fullWidth',
+})<{ fullWidth?: boolean }>`
${commonButtonStyles};
border: none;
background-color: ${({ theme }) => theme.palette.primary.main};
@@ -45,7 +49,9 @@ export const PrimaryButton = styled.button<{ fullWidth?: boolean }>`
}
`;
-export const SecondaryButton = styled.button<{ active?: boolean; fullWidth?: boolean }>`
+export const SecondaryButton = styled.button.withConfig({
+ shouldForwardProp: (prop) => prop !== 'active' && prop !== 'fullWidth',
+})<{ active?: boolean; fullWidth?: boolean }>`
${commonButtonStyles};
color: ${({ theme }) => theme.palette.neutral.shade1};
background-color: transparent;
diff --git a/src/core/components/HorizontalList/index.tsx b/src/core/components/HorizontalList/index.tsx
index 6745b777d..dec4f1a9f 100644
--- a/src/core/components/HorizontalList/index.tsx
+++ b/src/core/components/HorizontalList/index.tsx
@@ -65,7 +65,9 @@ function findColumnByWidth(width: number, columns: { [width: number]: number })
return founded[1];
}
-const StretchedList = styled.div<{ currentWidth: number; columns: { [width: number]: number } }>`
+const StretchedList = styled.div.withConfig({
+ shouldForwardProp: (prop) => prop !== 'currentWidth' && prop !== 'columns',
+})<{ currentWidth: number; columns: { [width: number]: number } }>`
margin-bottom: 0.188rem; // give the shadow a little space
display: grid;
grid-auto-flow: column;
diff --git a/src/core/components/OptionMenu/styles.tsx b/src/core/components/OptionMenu/styles.tsx
index eb710ae9b..6095e4035 100644
--- a/src/core/components/OptionMenu/styles.tsx
+++ b/src/core/components/OptionMenu/styles.tsx
@@ -28,6 +28,8 @@ export const Option = styled.div<{ active?: boolean }>`
}
`;
-export const Container = styled.div<{ pullRight?: boolean }>`
+export const Container = styled.div.withConfig({
+ shouldForwardProp: (prop) => prop !== 'pullRight',
+})<{ pullRight?: boolean }>`
${({ pullRight }) => pullRight && `margin-left: auto;`}
`;
diff --git a/src/core/components/SideBar/styles.tsx b/src/core/components/SideBar/styles.tsx
index 4f488c252..11dddb7a6 100644
--- a/src/core/components/SideBar/styles.tsx
+++ b/src/core/components/SideBar/styles.tsx
@@ -19,7 +19,9 @@ export const MenuName = styled.div`
white-space: normal;
`;
-export const MenuTabContainer = styled.div<{ active?: boolean }>`
+export const MenuTabContainer = styled.div.withConfig({
+ shouldForwardProp: (prop) => prop !== 'active',
+})<{ active?: boolean }>`
flex-direction: column;
display: flex;
align-items: center;
diff --git a/src/core/components/SideMenuActionItem/styles.tsx b/src/core/components/SideMenuActionItem/styles.tsx
index aa464daaa..db5e98d0f 100644
--- a/src/core/components/SideMenuActionItem/styles.tsx
+++ b/src/core/components/SideMenuActionItem/styles.tsx
@@ -47,7 +47,9 @@ export const AnchorActionItem = styled.a<{ active?: boolean }>`
`};
`;
-export const IconWrapper = styled.div<{ active?: boolean }>`
+export const IconWrapper = styled.div.withConfig({
+ shouldForwardProp: (prop) => prop !== 'active',
+})<{ active?: boolean }>`
width: 40px;
height: 40px;
border-radius: 4px;
diff --git a/src/core/components/SideMenuItem/styles.tsx b/src/core/components/SideMenuItem/styles.tsx
index 5f33f79fc..fe1fe93cc 100644
--- a/src/core/components/SideMenuItem/styles.tsx
+++ b/src/core/components/SideMenuItem/styles.tsx
@@ -30,7 +30,9 @@ export const SideMenuItemContainer = styled(SecondaryButton)`
`}
`;
-export const IconWrapper = styled.div<{ active?: boolean }>`
+export const IconWrapper = styled.div.withConfig({
+ shouldForwardProp: (prop) => prop !== 'active',
+})<{ active?: boolean }>`
width: 40px;
height: 40px;
border-radius: 4px;
@@ -38,6 +40,7 @@ export const IconWrapper = styled.div<{ active?: boolean }>`
align-items: center;
justify-content: center;
margin-right: 8px;
+
${({ active, theme }) =>
active
? css`
diff --git a/src/core/components/Time/index.tsx b/src/core/components/Time/index.tsx
index df28ec7f6..ff259acf5 100644
--- a/src/core/components/Time/index.tsx
+++ b/src/core/components/Time/index.tsx
@@ -12,11 +12,17 @@ export interface TimeProps {
}
const Time = ({ className, date = Date.now() }: TimeProps) => {
+ const isValidDate = !isNaN(date) && new Date(date).getTime() > 0;
const delta = Date.now() - date;
return (
- {delta < DAY ? : }
+ {isValidDate &&
+ (delta < DAY ? (
+
+ ) : (
+
+ ))}
);
};
diff --git a/src/core/components/Uploaders/Image/styles.tsx b/src/core/components/Uploaders/Image/styles.tsx
index da6a7cc54..7d00a17c8 100644
--- a/src/core/components/Uploaders/Image/styles.tsx
+++ b/src/core/components/Uploaders/Image/styles.tsx
@@ -8,7 +8,9 @@ import Skeleton from '~/core/components/Skeleton';
import RemoveIcon from '~/icons/Remove';
import ExclamationCircle from '~/icons/ExclamationCircle';
-export const ImageContainer = styled.div<{ border?: boolean }>`
+export const ImageContainer = styled.div.withConfig({
+ shouldForwardProp: (prop) => prop !== 'border',
+})<{ border?: boolean }>`
position: relative;
display: inline-block;
min-width: 2em;
@@ -38,9 +40,13 @@ const ImgPreviewContainerStyles = css<{ mediaFit?: string; loading?: string }>`
object-position: center;
`;
-export const ImgPreview = styled.img.attrs<{ mediaFit?: string; loading?: string }>({
- loading: 'lazy',
-})`
+export const ImgPreview = styled.img
+ .withConfig({
+ shouldForwardProp: (prop) => prop !== 'mediaFit',
+ })
+ .attrs<{ mediaFit?: string; loading?: string }>({
+ loading: 'lazy',
+ })`
${ImgPreviewContainerStyles}
`;
diff --git a/src/core/components/Uploaders/Video/styles.tsx b/src/core/components/Uploaders/Video/styles.tsx
index 020702fd5..22f562c9a 100644
--- a/src/core/components/Uploaders/Video/styles.tsx
+++ b/src/core/components/Uploaders/Video/styles.tsx
@@ -8,7 +8,9 @@ import LiveBadge from '~/social/components/LiveBadge';
import { ExclamationCircle, Play, Remove } from '~/icons';
-export const VideoContainer = styled.div<{ border?: boolean }>`
+export const VideoContainer = styled.div.withConfig({
+ shouldForwardProp: (prop) => prop !== 'border',
+})<{ border?: boolean }>`
position: relative;
display: inline-block;
min-width: 2em;
diff --git a/src/social/components/CommunityInfo/styles.tsx b/src/social/components/CommunityInfo/styles.tsx
index 5f3ab2dcb..6af0190b9 100644
--- a/src/social/components/CommunityInfo/styles.tsx
+++ b/src/social/components/CommunityInfo/styles.tsx
@@ -32,7 +32,9 @@ export const Container = styled.div`
margin-bottom: 12px;
`;
-export const Cover = styled.div<{ backgroundImage?: string }>`
+export const Cover = styled.div.withConfig({
+ shouldForwardProp: (prop) => prop !== 'backgroundImage',
+})<{ backgroundImage?: string }>`
padding-top: 56.25%;
position: relative;
diff --git a/src/social/components/SocialSearch/styles.tsx b/src/social/components/SocialSearch/styles.tsx
index 78c5c7586..989ffbaac 100644
--- a/src/social/components/SocialSearch/styles.tsx
+++ b/src/social/components/SocialSearch/styles.tsx
@@ -13,7 +13,9 @@ export const SearchIcon = styled(Search).attrs({ width: 16, height: 16 })`
fill: ${({ theme }) => theme.palette.base.shade2};
`;
-export const SocialSearchContainer = styled.div<{ sticky?: boolean }>`
+export const SocialSearchContainer = styled.div.withConfig({
+ shouldForwardProp: (prop) => prop !== 'sticky',
+})<{ sticky?: boolean }>`
position: relative;
${({ sticky }) =>
diff --git a/src/social/components/community/Card/styles.tsx b/src/social/components/community/Card/styles.tsx
index a81117cf8..95548d090 100644
--- a/src/social/components/community/Card/styles.tsx
+++ b/src/social/components/community/Card/styles.tsx
@@ -12,7 +12,9 @@ export const Container = styled.div`
overflow: hidden;
`;
-export const Cover = styled.div<{ backgroundImage?: string }>`
+export const Cover = styled.div.withConfig({
+ shouldForwardProp: (prop) => prop !== 'backgroundImage',
+})<{ backgroundImage?: string }>`
padding-top: 74.46%;
position: relative;
diff --git a/src/social/components/community/CategoryCard/styles.tsx b/src/social/components/community/CategoryCard/styles.tsx
index 23ccaee4d..4d2c33d8a 100644
--- a/src/social/components/community/CategoryCard/styles.tsx
+++ b/src/social/components/community/CategoryCard/styles.tsx
@@ -1,6 +1,8 @@
import styled from 'styled-components';
-export const Container = styled.div<{ backgroundImage?: string }>`
+export const Container = styled.div.withConfig({
+ shouldForwardProp: (prop) => prop !== 'backgroundImage',
+})<{ backgroundImage?: string }>`
min-width: 160px;
min-height: 150px;
cursor: pointer;
diff --git a/src/social/components/community/Header/styles.tsx b/src/social/components/community/Header/styles.tsx
index 462a70f25..5a23a29ce 100644
--- a/src/social/components/community/Header/styles.tsx
+++ b/src/social/components/community/Header/styles.tsx
@@ -8,9 +8,9 @@ interface CommunityHeaderContainerProps {
isActive?: boolean;
}
-export const CommunityHeaderContainer = styled.a.attrs(
- (props) => props,
-)`
+export const CommunityHeaderContainer = styled.a.withConfig({
+ shouldForwardProp: (prop) => !['loading', 'isActive'].includes(prop),
+})`
display: grid;
grid-template-areas: 'avatar title' 'avatar children';
grid-template-columns: min-content auto;
diff --git a/src/social/components/community/Name/styles.tsx b/src/social/components/community/Name/styles.tsx
index d60264246..f672ad84d 100644
--- a/src/social/components/community/Name/styles.tsx
+++ b/src/social/components/community/Name/styles.tsx
@@ -19,7 +19,9 @@ export const Name = styled.div`
padding-right: 1ch;
`;
-export const NameContainer = styled.div<{
+export const NameContainer = styled.div.withConfig({
+ shouldForwardProp: (prop) => prop !== 'isActive' && prop !== 'isTitle',
+})<{
isActive?: boolean;
isTitle?: boolean;
}>`
diff --git a/src/social/components/community/TrendingItem/UITrendingItem.tsx b/src/social/components/community/TrendingItem/UITrendingItem.tsx
index 87691a5f5..e0b43cdbd 100644
--- a/src/social/components/community/TrendingItem/UITrendingItem.tsx
+++ b/src/social/components/community/TrendingItem/UITrendingItem.tsx
@@ -21,7 +21,9 @@ const ItemContainer = styled.div`
overflow: hidden;
`;
-const Cover = styled.div<{ backgroundImage?: string }>`
+const Cover = styled.div.withConfig({
+ shouldForwardProp: (prop) => prop !== 'backgroundImage',
+})<{ backgroundImage?: string }>`
padding-left: 100%;
${({ backgroundImage, theme }) => `
diff --git a/src/social/components/post/ChildrenContent/index.tsx b/src/social/components/post/ChildrenContent/index.tsx
index e960f794e..11727ef9c 100644
--- a/src/social/components/post/ChildrenContent/index.tsx
+++ b/src/social/components/post/ChildrenContent/index.tsx
@@ -49,7 +49,7 @@ const ChildrenContent = ({ contents }: { contents: Amity.Post[] }) => {
return (
<>
{items.map((poll) => (
-
+
))}
>
);
diff --git a/src/social/components/post/GalleryContent/ImageItem.tsx b/src/social/components/post/GalleryContent/ImageItem.tsx
index beeb462fc..4a3a82135 100644
--- a/src/social/components/post/GalleryContent/ImageItem.tsx
+++ b/src/social/components/post/GalleryContent/ImageItem.tsx
@@ -8,6 +8,7 @@ interface ThumbnailProps {
export const Thumbnail = ({ item }: ThumbnailProps) => {
return (
{
return (
`
+export const AdditionalInfo = styled.div.withConfig({
+ shouldForwardProp: (prop) => prop !== 'showTime',
+})<{ showTime?: boolean }>`
display: flex;
align-items: center;
diff --git a/src/social/pages/NewsFeed/styles.tsx b/src/social/pages/NewsFeed/styles.tsx
index df00274b3..db23c6b64 100644
--- a/src/social/pages/NewsFeed/styles.tsx
+++ b/src/social/pages/NewsFeed/styles.tsx
@@ -32,7 +32,9 @@ export const MobileContainer = styled.div`
}
`;
-export const CommunitySideMenuOverlay = styled.div<{ isOpen: boolean }>`
+export const CommunitySideMenuOverlay = styled.div.withConfig({
+ shouldForwardProp: (prop) => prop !== 'isOpen',
+})<{ isOpen?: boolean }>`
position: fixed;
top: 0;
left: 0;
@@ -48,7 +50,9 @@ export const CommunitySideMenuOverlay = styled.div<{ isOpen: boolean }>`
cursor: pointer;
`;
-export const StyledCommunitySideMenu = styled(CommunitySideMenu)<{ isOpen: boolean }>`
+export const StyledCommunitySideMenu = styled(CommunitySideMenu).withConfig({
+ shouldForwardProp: (prop) => prop !== 'isOpen',
+})<{ isOpen?: boolean }>`
position: fixed;
top: 0;
left: 0;
diff --git a/src/v4/social/hooks/useVisibilitySensor.tsx b/src/v4/social/hooks/useVisibilitySensor.tsx
new file mode 100644
index 000000000..14243139c
--- /dev/null
+++ b/src/v4/social/hooks/useVisibilitySensor.tsx
@@ -0,0 +1,34 @@
+import { RefObject, useEffect, useState } from 'react';
+
+interface UseVisibilitySensorProps {
+ threshold: number;
+ elementRef: RefObject;
+}
+
+export const useVisibilitySensor = ({ threshold, elementRef }: UseVisibilitySensorProps) => {
+ const [isVisible, setIsVisible] = useState(false);
+
+ useEffect(() => {
+ if (!elementRef.current) return;
+
+ const observer = new IntersectionObserver(
+ (entries) => {
+ entries.forEach((entry) => {
+ const isIntersecting = entry.isIntersecting;
+ setIsVisible(isIntersecting);
+ });
+ },
+ {
+ threshold: threshold,
+ },
+ );
+
+ observer.observe(elementRef.current);
+
+ return () => {
+ observer.disconnect();
+ };
+ }, [threshold, elementRef]);
+
+ return { isVisible };
+};