From c76639c42edc87eba18c8b44ad8e053c0bcc1d4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sat, 12 Nov 2022 15:18:24 +0100 Subject: [PATCH] JS -> TS, FC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- app/soapbox/actions/modals.ts | 6 +- app/soapbox/actions/notifications.ts | 17 ++-- .../components/extended_video_player.js | Bin 1562 -> 0 bytes .../components/extended_video_player.tsx | 64 ++++++++++++ app/soapbox/components/modal_root.tsx | 5 +- app/soapbox/components/sidebar-navigation.tsx | 2 +- .../__tests__/notification.test.tsx | 2 +- .../components/placeholder_media_gallery.js | Bin 2507 -> 0 bytes .../components/placeholder_media_gallery.tsx | 93 ++++++++++++++++++ .../placeholder/{utils.js => utils.ts} | Bin 352 -> 378 bytes app/soapbox/features/ui/components/bundle.tsx | 6 +- .../features/ui/components/media-modal.tsx | 3 +- .../{modal_root.js => modal_root.tsx} | Bin 3138 -> 3358 bytes .../ui/containers/bundle_container.tsx | 3 +- ...{modal_container.js => modal_container.ts} | Bin 845 -> 966 bytes .../{notifications.js => notifications.ts} | Bin 7432 -> 8482 bytes 16 files changed, 179 insertions(+), 22 deletions(-) delete mode 100644 app/soapbox/components/extended_video_player.js create mode 100644 app/soapbox/components/extended_video_player.tsx delete mode 100644 app/soapbox/features/placeholder/components/placeholder_media_gallery.js create mode 100644 app/soapbox/features/placeholder/components/placeholder_media_gallery.tsx rename app/soapbox/features/placeholder/{utils.js => utils.ts} (68%) rename app/soapbox/features/ui/components/{modal_root.js => modal_root.tsx} (83%) rename app/soapbox/features/ui/containers/{modal_container.js => modal_container.ts} (65%) rename app/soapbox/reducers/{notifications.js => notifications.ts} (64%) diff --git a/app/soapbox/actions/modals.ts b/app/soapbox/actions/modals.ts index 3e1a106cf9..00d4fd01a4 100644 --- a/app/soapbox/actions/modals.ts +++ b/app/soapbox/actions/modals.ts @@ -1,8 +1,10 @@ +import type { ModalType } from 'soapbox/features/ui/components/modal_root'; + export const MODAL_OPEN = 'MODAL_OPEN'; export const MODAL_CLOSE = 'MODAL_CLOSE'; /** Open a modal of the given type */ -export function openModal(type: string, props?: any) { +export function openModal(type: ModalType, props?: any) { return { type: MODAL_OPEN, modalType: type, @@ -11,7 +13,7 @@ export function openModal(type: string, props?: any) { } /** Close the modal */ -export function closeModal(type?: string) { +export function closeModal(type?: ModalType) { return { type: MODAL_CLOSE, modalType: type, diff --git a/app/soapbox/actions/notifications.ts b/app/soapbox/actions/notifications.ts index db8fd688f0..8ef0e57156 100644 --- a/app/soapbox/actions/notifications.ts +++ b/app/soapbox/actions/notifications.ts @@ -1,6 +1,3 @@ -import { - Map as ImmutableMap, -} from 'immutable'; import IntlMessageFormat from 'intl-messageformat'; import 'intl-pluralrules'; import { defineMessages } from 'react-intl'; @@ -149,13 +146,13 @@ const updateNotificationsQueue = (notification: APIEntity, intlMessages: Record< const dequeueNotifications = () => (dispatch: AppDispatch, getState: () => RootState) => { - const queuedNotifications = getState().notifications.get('queuedNotifications'); - const totalQueuedNotificationsCount = getState().notifications.get('totalQueuedNotificationsCount'); + const queuedNotifications = getState().notifications.queuedNotifications; + const totalQueuedNotificationsCount = getState().notifications.totalQueuedNotificationsCount; if (totalQueuedNotificationsCount === 0) { return; } else if (totalQueuedNotificationsCount > 0 && totalQueuedNotificationsCount <= MAX_QUEUED_NOTIFICATIONS) { - queuedNotifications.forEach((block: APIEntity) => { + queuedNotifications.forEach((block) => { dispatch(updateNotifications(block.notification)); }); } else { @@ -184,7 +181,7 @@ const expandNotifications = ({ maxId }: Record = {}, done: () => an const notifications = state.notifications; const isLoadingMore = !!maxId; - if (notifications.get('isLoading')) { + if (notifications.isLoading) { done(); return dispatch(noOp); } @@ -207,7 +204,7 @@ const expandNotifications = ({ maxId }: Record = {}, done: () => an } } - if (!maxId && notifications.get('items').size > 0) { + if (!maxId && notifications.items.size > 0) { params.since_id = notifications.getIn(['items', 0, 'id']); } @@ -306,8 +303,8 @@ const markReadNotifications = () => if (!isLoggedIn(getState)) return; const state = getState(); - const topNotificationId: string | undefined = state.notifications.get('items').first(ImmutableMap()).get('id'); - const lastReadId: string | -1 = state.notifications.get('lastRead'); + const topNotificationId = state.notifications.items.first()?.id; + const lastReadId = state.notifications.lastRead; const v = parseVersion(state.instance.version); if (topNotificationId && (lastReadId === -1 || compareId(topNotificationId, lastReadId) > 0)) { diff --git a/app/soapbox/components/extended_video_player.js b/app/soapbox/components/extended_video_player.js deleted file mode 100644 index 59a6b938e5f6ea1629e316b7574948bf7bf43454..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1562 zcmbtUO>f&U487-9a3?1~;%?WqE-$>A0TTCNNmOP2hQW*K~qa?dk`hgvm zLlW~*wX-c09Y3!q1d8LCN;x+u8X9pI{xdXT11Nv_^&9L* z+*{Grc6X%w&(_vTW5~r_>?Lt6dQH%1;XPdJ2#rK}rzF~IEgsMT#+ZlLvApgbo>}H# z&=3r>8Gt82s)4{Vv934{{PC{&_;i`llT+rtRQ?8k_sXGM#w?-fWmbazC`p?fG<{p6 zOW+38{pR3kj*@Eet&@#4UZ>0oCa!lUl=^Hp-VlL0<;uixC2dz&6-XHobE!`Yq#J;n|7fsO3KN3@w|< zqH`rb+ujg2Or~T7g_IXtu6U(9+m3Et=*Uqr$6}c}JmaBPfhEK_T82(>?v}ta&)b=sn0lmB{4G_WDD)@drKx!g zJ!cO*PGPSCleppY#ndid~U;~n;wMk^C$rue{{A1Xw~01l~l2Iesaa3a+`zg4J(t~edDIX}i9A49!$HAG{QXJH(t4+~KZ{FTQJXTC96 zQ)F=x^(70utBUt|SU4qCTGXhkfkn-WlOitlJQ}U2hWL|bPu^6+^e;!XwOuv5dkq?A fWW0Aae);*KEX!A2eM&l-bUis@8`8tHZ2Q??QmyBD diff --git a/app/soapbox/components/extended_video_player.tsx b/app/soapbox/components/extended_video_player.tsx new file mode 100644 index 0000000000..99a0af01c4 --- /dev/null +++ b/app/soapbox/components/extended_video_player.tsx @@ -0,0 +1,64 @@ +import React, { useEffect, useRef } from 'react'; + +import { isIOS } from 'soapbox/is_mobile'; + +interface IExtendedVideoPlayer { + src: string, + alt?: string, + width?: number, + height?: number, + time?: number, + controls?: boolean, + muted?: boolean, + onClick?: () => void, +} + +const ExtendedVideoPlayer: React.FC = ({ src, alt, time, controls, muted, onClick }) => { + const video = useRef(null); + + useEffect(() => { + const handleLoadedData = () => { + if (time) { + video.current!.currentTime = time; + } + }; + + video.current?.addEventListener('loadeddata', handleLoadedData); + + return () => { + video.current?.removeEventListener('loadeddata', handleLoadedData); + }; + }, [video.current]); + + const handleClick: React.MouseEventHandler = e => { + e.stopPropagation(); + const handler = onClick; + if (handler) handler(); + }; + + const conditionalAttributes: React.VideoHTMLAttributes = {}; + if (isIOS()) { + conditionalAttributes.playsInline = true; + } + + return ( +
+
+ ); +}; + +export default ExtendedVideoPlayer; diff --git a/app/soapbox/components/modal_root.tsx b/app/soapbox/components/modal_root.tsx index f34597d5b5..d17be3efc4 100644 --- a/app/soapbox/components/modal_root.tsx +++ b/app/soapbox/components/modal_root.tsx @@ -9,6 +9,7 @@ import { openModal, closeModal } from 'soapbox/actions/modals'; import { useAppDispatch, useAppSelector, usePrevious } from 'soapbox/hooks'; import type { UnregisterCallback } from 'history'; +import type { ModalType } from 'soapbox/features/ui/components/modal_root'; import type { ReducerCompose } from 'soapbox/reducers/compose'; const messages = defineMessages({ @@ -26,8 +27,8 @@ export const checkComposeContent = (compose?: ReturnType) interface IModalRoot { onCancel?: () => void, - onClose: (type?: string) => void, - type: string, + onClose: (type?: ModalType) => void, + type: ModalType, } const ModalRoot: React.FC = ({ children, onCancel, onClose, type }) => { diff --git a/app/soapbox/components/sidebar-navigation.tsx b/app/soapbox/components/sidebar-navigation.tsx index 583006070d..22ad8dfc98 100644 --- a/app/soapbox/components/sidebar-navigation.tsx +++ b/app/soapbox/components/sidebar-navigation.tsx @@ -28,7 +28,7 @@ const SidebarNavigation = () => { const instance = useAppSelector((state) => state.instance); const settings = useAppSelector((state) => getSettings(state)); const account = useOwnAccount(); - const notificationCount = useAppSelector((state) => state.notifications.get('unread')); + const notificationCount = useAppSelector((state) => state.notifications.unread); const chatsCount = useAppSelector((state) => state.chats.items.reduce((acc, curr) => acc + Math.min(curr.unread || 0, 1), 0)); const followRequestsCount = useAppSelector((state) => state.user_lists.follow_requests.items.count()); const dashboardCount = useAppSelector((state) => state.admin.openReports.count() + state.admin.awaitingApproval.count()); diff --git a/app/soapbox/features/notifications/components/__tests__/notification.test.tsx b/app/soapbox/features/notifications/components/__tests__/notification.test.tsx index 9c86474b7b..b9c5df6414 100644 --- a/app/soapbox/features/notifications/components/__tests__/notification.test.tsx +++ b/app/soapbox/features/notifications/components/__tests__/notification.test.tsx @@ -13,7 +13,7 @@ const normalize = (notification: any) => { return { // @ts-ignore - notification: state.notifications.items.get(notification.id), + notification: state.notifications.items.get(notification.id)!, state, }; }; diff --git a/app/soapbox/features/placeholder/components/placeholder_media_gallery.js b/app/soapbox/features/placeholder/components/placeholder_media_gallery.js deleted file mode 100644 index c1b2dd3b9dccbdf73cc4561e0526f9decbe6dd9a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2507 zcmdT`OHbQC5WeSE%%!qZISx=-sep4SQpJG^(Mmlagf{V*tXMy~yW!E`|K8bMuOCT7 zp||E_ufO@`o7s7U=T#{+tl^whz!aS2`AW07K=WQhCd(WG?hk|G5qAa`vaEhQRj3+B zMeh@B4m!*wvW0HGOY_`)YTaz|Slpy_I5E7Qc7%^sY>F9M2@MOul!6Pv7Pu@$it-#& z&b~4sP(A@ZYAjL(Rz>`!B;5rT6zXUMpfuBb0fya0k0Tw|_Id5(qR zB!MWet{Wqh2q!X0V1L}C$6PSc#7pG2OHFv^_dR@uDeQl0Y+)C%&4#IjH9Qq*1UE*^c%}D3GC{d+`9F7 zb7O8baC0I8x^0iyL zFRT(%OU+8Mi>|k&LaRGA2-;=+KtuZiU<0;)7Ip;cT>G#mldAhW(MIpR$K*B)Z0!f* zni?ca)>clts_R+flO~kYrP&>Zhhy{iAq;PPWm~JR{Ot-e@i`A04Hb;9__eVdn=NgA QCsVpZ=gRJHN^L#*0|cwy; + defaultWidth?: number; +} + +const SizeData = ImmutableRecord({ + style: {} as React.CSSProperties, + itemsDimensions: [] as Record[], + size: 1 as number, + width: 0 as number, +}); + +const PlaceholderMediaGallery: React.FC = ({ media, defaultWidth }) => { + const [width, setWidth] = useState(defaultWidth); + + const handleRef = (node: HTMLDivElement) => { + if (node) { + setWidth(node.offsetWidth); + } + }; + + const getSizeData = (size: number) => { + const style: React.CSSProperties = {}; + let itemsDimensions: Record[] = []; + + if (size === 1) { + style.height = width! * 9 / 16; + + itemsDimensions = [ + { w: '100%', h: '100%' }, + ]; + } else if (size === 2) { + style.height = width! / 2; + + itemsDimensions = [ + { w: '50%', h: '100%', r: '2px' }, + { w: '50%', h: '100%', l: '2px' }, + ]; + } else if (size === 3) { + style.height = width; + + itemsDimensions = [ + { w: '50%', h: '50%', b: '2px', r: '2px' }, + { w: '50%', h: '50%', b: '2px', l: '2px' }, + { w: '100%', h: '50%', t: '2px' }, + ]; + } else if (size >= 4) { + style.height = width; + + itemsDimensions = [ + { w: '50%', h: '50%', b: '2px', r: '2px' }, + { w: '50%', h: '50%', b: '2px', l: '2px' }, + { w: '50%', h: '50%', t: '2px', r: '2px' }, + { w: '50%', h: '50%', t: '2px', l: '2px' }, + ]; + } + + return SizeData({ + style, + itemsDimensions, + size, + width, + }); + }; + + const renderItem = (dimensions: Record, i: number) => { + const width = dimensions.w; + const height = dimensions.h; + const top = dimensions.t || 'auto'; + const right = dimensions.r || 'auto'; + const bottom = dimensions.b || 'auto'; + const left = dimensions.l || 'auto'; + const float = dimensions.float as any || 'left'; + const position = dimensions.pos as any || 'relative'; + + return
; + }; + + const sizeData = getSizeData(media.size); + + return ( +
+ {media.take(4).map((_, i) => renderItem(sizeData.get('itemsDimensions')[i], i))} +
+ ); +}; + +export default PlaceholderMediaGallery; diff --git a/app/soapbox/features/placeholder/utils.js b/app/soapbox/features/placeholder/utils.ts similarity index 68% rename from app/soapbox/features/placeholder/utils.js rename to app/soapbox/features/placeholder/utils.ts index f2001a61d530b543ca502532503212a02379479b..15eb4e5e52b957346c2edc3b2fcf1f2147c34253 100644 GIT binary patch delta 52 vcmaFB^owbNi-1N>YF>IthLu8IX>L+#k>*6N)1okrjzVr?1&lLUiqQ=K{bUk= delta 26 hcmeyx^nhuC3tLWVUV2H!#E{dhItsao6_ZUE-2jX)36KB) diff --git a/app/soapbox/features/ui/components/bundle.tsx b/app/soapbox/features/ui/components/bundle.tsx index 55f6478bca..79851b9789 100644 --- a/app/soapbox/features/ui/components/bundle.tsx +++ b/app/soapbox/features/ui/components/bundle.tsx @@ -3,10 +3,10 @@ import React from 'react'; const emptyComponent = () => null; const noop = () => { }; -interface BundleProps { +export interface BundleProps { fetchComponent: () => Promise, loading: React.ComponentType, - error: React.ComponentType<{ onRetry: (props: BundleProps) => void }>, + error: React.ComponentType<{ onRetry: (props?: BundleProps) => void }>, children: (mod: any) => React.ReactNode, renderDelay?: number, onFetch: () => void, @@ -57,7 +57,7 @@ class Bundle extends React.PureComponent { } } - load = (props: BundleProps) => { + load = (props?: BundleProps) => { const { fetchComponent, onFetch, onFetchSuccess, onFetchFail, renderDelay } = props || this.props; const cachedMod = Bundle.cache.get(fetchComponent); diff --git a/app/soapbox/features/ui/components/media-modal.tsx b/app/soapbox/features/ui/components/media-modal.tsx index 92b5ecad98..1a432de3b7 100644 --- a/app/soapbox/features/ui/components/media-modal.tsx +++ b/app/soapbox/features/ui/components/media-modal.tsx @@ -225,7 +225,6 @@ const MediaModal: React.FC = (props) => { muted controls={false} width={width} - link={link} height={height} key={attachment.preview_url} alt={attachment.description} @@ -298,4 +297,4 @@ const MediaModal: React.FC = (props) => { ); }; -export default MediaModal; \ No newline at end of file +export default MediaModal; diff --git a/app/soapbox/features/ui/components/modal_root.js b/app/soapbox/features/ui/components/modal_root.tsx similarity index 83% rename from app/soapbox/features/ui/components/modal_root.js rename to app/soapbox/features/ui/components/modal_root.tsx index 32425cffd375f17c40a19526c5a304d93bd06103..f9900d569b5b8e1d9ed4e6c2c80a52d997a477c4 100644 GIT binary patch delta 411 zcmYk2K}*9x5QV`AwLt_=iU*mC*kX)$@etFL8a)(DThiVoO*RrtcEV;`2r+o}oV!;& ziv9!tjsL>ksBKQWJZ9ee=6&tI9K0*aQIw>}I23TTpg~L~4ATrs2pJ}Dte?$m^+UPX zeByaZz`?+aXY$vB2a;n5QWlRhz8>7(*<)ui9^H&)Q+Ncrh~rCDjVLE9^n3!tdfP=5 zc`DSK#@bO6QYz#72DrpW7MK}l5xv*Iqq%kd=P1XJ+A(ItfR0QT^DC?_^ek9n6liK$ zowm#!a~*0yQGK_lZZtqN5lNO)?s4HJVl>gjGRmTPOrWfl3b)>NJBhq|7#Q%2)U6KN u&jZQn`CPYAlt>BXvKX@vcrM{A7kK~oG|F8OLTOd6?R2|||GB50Z2SPvlZw;; delta 200 zcmbOybx2|ZGxKI`W@DDg;vB~H3e{X(3JS#~i6xoI3I#>^1tFCMsl^JmKyd{iC;{@U z6arx4dc`G0nR)3tU^$TLVr0quq^#8B5{P7eo^wuqF^b-_(!6B7%;KQb!qUv5)D)1q zT1M;15gd6EIzX#a%YuQfNYzoORw&CX&P>WlRj8f(g<}PKZhlH)j%Ui`wVa)k%ee|R Jf9BF=0stPaLiYdw diff --git a/app/soapbox/features/ui/containers/bundle_container.tsx b/app/soapbox/features/ui/containers/bundle_container.tsx index 12e4b37877..50a8b8629b 100644 --- a/app/soapbox/features/ui/containers/bundle_container.tsx +++ b/app/soapbox/features/ui/containers/bundle_container.tsx @@ -1,6 +1,7 @@ import { connect } from 'react-redux'; -import { fetchBundleRequest, fetchBundleSuccess, fetchBundleFail } from '../../../actions/bundles'; +import { fetchBundleRequest, fetchBundleSuccess, fetchBundleFail } from 'soapbox/actions/bundles'; + import Bundle from '../components/bundle'; import type { AppDispatch } from 'soapbox/store'; diff --git a/app/soapbox/features/ui/containers/modal_container.js b/app/soapbox/features/ui/containers/modal_container.ts similarity index 65% rename from app/soapbox/features/ui/containers/modal_container.js rename to app/soapbox/features/ui/containers/modal_container.ts index 54f07a371f077e58bd41b2ef226143233d22d8f2..dc24254c399588c355174503386a31b089ac7664 100644 GIT binary patch delta 205 zcmX@hc8q<(6Mh|qY6ai?l*F8n%7Rpd+KEq;>oao;@{39oNegIb$@zK3B?`HT1z>d{`2j`w z1;q-s3L3>AeO3q~G!<;^6soxt6regljsU7F<_4+L%LQ?ZC;KwSuqq@LEBH=c$QZ(A W1$NEkcZ{-}_Eu15Z{}cfWds1uZALl( delta 54 zcmX@cewJ;*lZl^|CxX=SW5&i zDhT3B(W@T3c#?P!JbLQUgP<4v1KtEd58~`*v)N?Zo|bv%nfH0#&wW&UeQK9sRUOLF zf`rf%t|H7(*|J=YD<%jS%nBAWS@zG{`o`+F z4V<~N4i2XVkFM2nDl#$S<#@i~$A(YvO4^Nz$nPq(Yf3^H@LAfC$h^M> zAk~ZV9m2)jgio&DRA99C&9N0-cLD`1ndcqdV497ey`zb?FiK2+$l07xjj+IQ-_;D( zG{?0$JnuUxS|o@hFqU@KnA z)=G6kd7hoj1>BJin9lCcc(jT#2BUol-e&g>hEhdhi>Tr_Cc!p*$+DsFhKX5sS-Wyx zxap=5K5QPp76Ln)GAx4HwbfSHXFjU6&6;Zm^10#u+p!(X;C^mjkHLw>U^#aP5?gjQ z_H22U7+P)gWq99z7XI}=+#hPSFug@+B(>3;V!Kv?#{(C#?d16z5WWuF4S25)ek=se z{4Eq&da|M-?Eh~>(Z#O^hPVFR$OxAUzT^VD%WZEQ*>)z?ZG@*ger*bCEd-Aj delta 707 zcmZ8f&ubGw6ehMY$(l{lB-`CaX{I3ET{{M?cxknWC>W!7=&|;&?oQgl{l(7IT7n0? z=%t`OyeNqDU~gjGqX!Rq@IMg5t4C1}UW%ZTO{iTj1Mho$@B6+tZ|nSnxjgm4AmXUE z)7%_^?a>R6%lhyr`^3P~9dlli?7(Lng;vB!+d*d$70<%3_PIeFIGtM;{o+u}6vVLk7{xBM)ag;^klqv_^W;d%;)Rq57&JVvg? zc-w(b#rN<`o_Z{+@Kvr#i3$%w-HdnTQU*%eK~TyKdA}ZmPWh#RQ3?|!xy@sb;^my^aPjY_oBe- z@k!WJ@_XcWYBRfx(Frqtqdd&OlG=f7^`7`3&x&r62o|+#u%oRP6R(4rCLEu53*RRi zP;dMyIm9KLh}%f?;+eyp(Q+Cy;b-Lt+;7z2WAj738wK9wMZ>cDx6>M`yh8jhh57DN