Migrate most types to pl-hooks

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak 2024-10-23 23:27:55 +02:00
parent 34ee036168
commit 832d0dff2e
33 changed files with 74 additions and 70 deletions

View file

@ -16,7 +16,7 @@ import { useAccountHoverCardStore } from 'bigbuffet/stores/account-hover-card';
import { ParsedContent } from './parsed-content';
import type { Account } from 'bigbuffet/normalizers/account';
import type { UseAccountData as Account } from 'pl-hooks';
const showAccountHoverCard = debounce((openAccountHoverCard, ref, accountId) => {
openAccountHoverCard(ref, accountId);

View file

@ -11,7 +11,7 @@ import Emojify from 'bigbuffet/features/emoji';
import ActionButton from 'bigbuffet/features/ui/components/action-button';
import { getAcct } from 'bigbuffet/utils/accounts';
import type { Account as AccountSchema } from 'bigbuffet/normalizers/account';
import type { UseAccountData as AccountEntity } from 'pl-hooks';
interface IProfilePopper {
condition: boolean;
@ -26,7 +26,7 @@ const ProfilePopper: React.FC<IProfilePopper> = ({ condition, wrapper, children
);
export interface IAccount {
account: AccountSchema;
account: AccountEntity;
action?: React.ReactElement;
/** Override other actions for specificity like mute/unmute. */
hidden?: boolean;

View file

@ -8,7 +8,7 @@ import { getAcct } from '../utils/accounts';
import VerificationBadge from './verification-badge';
import type { Account } from 'bigbuffet/normalizers/account';
import type { UseAccountData as Account } from 'pl-hooks';
interface IDisplayName {
account: Pick<Account, 'id' | 'acct' | 'fqn' | 'verified' | 'display_name' | 'emojis'>;

View file

@ -8,14 +8,14 @@ import Emojify from 'bigbuffet/features/emoji';
import EventActionButton from 'bigbuffet/features/event/components/event-action-button';
import EventDate from 'bigbuffet/features/event/components/event-date';
import type { Status as StatusEntity } from 'bigbuffet/normalizers/status';
import type { UseStatusData as Status } from 'pl-hooks';
const messages = defineMessages({
eventBanner: { id: 'event.banner', defaultMessage: 'Event banner' },
});
interface IEventPreview {
status: Pick<StatusEntity, 'id' | 'account' | 'event' | 'url'>;
status: Pick<Status, 'id' | 'account' | 'event' | 'url'>;
className?: string;
hideAction?: boolean;
floatingAction?: boolean;

View file

@ -8,8 +8,8 @@ import { isMobile } from 'bigbuffet/is-mobile';
import { useAccountHoverCardStore } from 'bigbuffet/stores/account-hover-card';
const showAccountHoverCard = debounce((
openAccountHoverCard: (ref: React.MutableRefObject<HTMLDivElement>, accountId: string) => void,
ref: React.MutableRefObject<HTMLDivElement>,
openAccountHoverCard: (ref: React.MutableRefObject<HTMLDivElement | null>, accountId: string) => void,
ref: React.MutableRefObject<HTMLDivElement | null>,
accountId: string,
) => {
if (ref.current) openAccountHoverCard(ref, accountId);

View file

@ -6,8 +6,8 @@ import { isMobile } from 'bigbuffet/is-mobile';
import { useStatusHoverCardStore } from 'bigbuffet/stores/status-hover-card';
const showStatusHoverCard = debounce((
openStatusHoverCard: (ref: React.MutableRefObject<HTMLDivElement>, accountId: string) => void,
ref: React.MutableRefObject<HTMLDivElement>,
openStatusHoverCard: (ref: React.MutableRefObject<HTMLDivElement | null>, accountId: string) => void,
ref: React.MutableRefObject<HTMLDivElement | null>,
statusId: string,
) => {
openStatusHoverCard(ref, statusId);

View file

@ -3,7 +3,7 @@ import { useHistory } from 'react-router-dom';
import StatusMedia from 'bigbuffet/components/status-media';
import AccountContainer from 'bigbuffet/containers/account-container';
import { useShowMedia } from 'bigbuffet/hooks/useShowMedia';
import { useStatusMetaStore } from 'bigbuffet/stores/status-meta';
import EventPreview from './event-preview';
import OutlineBox from './outline-box';
@ -11,20 +11,21 @@ import StatusContent from './status-content';
import StatusReplyMentions from './status-reply-mentions';
import SensitiveContentOverlay from './statuses/sensitive-content-overlay';
import type { SelectedStatus } from 'bigbuffet/selectors';
import type { UseStatusData as Status } from 'pl-hooks';
interface IQuotedStatus {
/** The quoted status entity. */
status?: SelectedStatus;
status: Status;
}
/** Status embedded in a quote post. */
const QuotedStatus: React.FC<IQuotedStatus> = ({ status }) => {
const history = useHistory();
const { statuses: statusesMeta, hideStatus, revealStatus } = useStatusMetaStore();
const overlay = useRef<HTMLDivElement>(null);
const showMedia = useShowMedia(status);
const showMedia = statusesMeta[status.id]?.visible ?? !status.sensitive;
const [minHeight, setMinHeight] = useState(208);
useEffect(() => {
@ -50,7 +51,11 @@ const QuotedStatus: React.FC<IQuotedStatus> = ({ status }) => {
};
const handleToggleMediaVisibility = () => {
setShowMedia(!showMedia);
if (showMedia) {
hideStatus(status.id);
} else {
revealStatus(status.id);
}
};
if (!status) {

View file

@ -10,8 +10,8 @@ import { onlyEmoji as isOnlyEmoji } from 'bigbuffet/utils/rich-content';
import { ParsedContent } from './parsed-content';
import Poll from './polls/poll';
import type { MinifiedStatus } from 'bigbuffet/reducers/statuses';
import type { Mention } from 'pl-api';
import type { UseStatusData as Status } from 'pl-hooks';
const MAX_HEIGHT = 642; // 20px * 16 (+ 2px padding at the top)
const BIG_EMOJI_LIMIT = 10;
@ -29,7 +29,7 @@ const ReadMoreButton: React.FC<IReadMoreButton> = ({ to }) => (
);
interface IStatusContent {
status: MinifiedStatus;
status: Status;
collapsable?: boolean;
}

View file

@ -4,8 +4,8 @@ import PreviewCard from 'bigbuffet/components/preview-card';
import { MediaGallery, Video, Audio } from 'bigbuffet/features/ui/util/async-components';
import { useModalsStore } from 'bigbuffet/stores/modals';
import type { Status } from 'bigbuffet/normalizers/status';
import type { MediaAttachment } from 'pl-api';
import type { UseStatusData as Status } from 'pl-hooks';
interface IStatusMedia {
/** Status entity to render media for. */

View file

@ -6,7 +6,7 @@ import HoverAccountWrapper from 'bigbuffet/components/hover-account-wrapper';
import HoverStatusWrapper from 'bigbuffet/components/hover-status-wrapper';
import { useModalsStore } from 'bigbuffet/stores/modals';
import type { Status } from 'bigbuffet/normalizers/status';
import type { UseStatusData as Status } from 'pl-hooks';
interface IStatusReplyMentions {
status: Pick<Status, 'in_reply_to_id' | 'id' | 'mentions'>;

View file

@ -22,7 +22,7 @@ import StatusReplyMentions from './status-reply-mentions';
import SensitiveContentOverlay from './statuses/sensitive-content-overlay';
import Card from './ui/card';
import type { SelectedStatus } from 'bigbuffet/selectors';
import type { UseStatusData as StatusEntity } from 'pl-hooks';
// Defined in components/scrollable-list
export type ScrollPosition = { height: number; top: number };
@ -33,7 +33,7 @@ const messages = defineMessages({
export interface IStatus {
id?: string;
status: SelectedStatus;
status: StatusEntity;
onMoveUp?: (statusId: string, featured?: boolean) => void;
onMoveDown?: (statusId: string, featured?: boolean) => void;
focusable?: boolean;
@ -75,20 +75,12 @@ const Status: React.FC<IStatus> = (props) => {
didShowCard.current = Boolean(status?.card);
}, []);
useEffect(() => {
setShowMedia(!status.sensitive);
}, [status.id]);
useEffect(() => {
if (overlay.current) {
setMinHeight(overlay.current.getBoundingClientRect().height);
}
}, [overlay.current]);
const handleToggleMediaVisibility = (): void => {
setShowMedia(!showMedia);
};
const handleClick = (e?: React.MouseEvent): void => {
e?.stopPropagation();
@ -134,7 +126,7 @@ const Status: React.FC<IStatus> = (props) => {
}
};
const handleHotkeyToggleHidden = (): void => {
const handleToggleMediaVisibility = (): void => {
if (showMedia) {
hideStatus(status.id);
} else {
@ -227,7 +219,7 @@ const Status: React.FC<IStatus> = (props) => {
openProfile: handleHotkeyOpenProfile,
moveUp: handleHotkeyMoveUp,
moveDown: handleHotkeyMoveDown,
toggleHidden: handleHotkeyToggleHidden,
toggleHidden: handleHotkeyToggleSensitive,
toggleSensitive: handleHotkeyToggleSensitive,
openMedia: handleHotkeyOpenMedia,
};

View file

@ -7,7 +7,7 @@ import { useStatusMetaStore } from 'bigbuffet/stores/status-meta';
import Button from '../ui/button';
import type { Status } from 'bigbuffet/normalizers/status';
import type { UseStatusData as Status } from 'pl-hooks';
const messages = defineMessages({
hide: { id: 'moderation_overlay.hide', defaultMessage: 'Hide content' },
@ -17,7 +17,7 @@ const messages = defineMessages({
});
interface ISensitiveContentOverlay {
status: Pick<Status, 'id' | 'sensitive' | 'media_attachments' | 'currentLanguage' | 'spoiler_text' | 'emojis'>;
status: Pick<Status, 'id' | 'sensitive' | 'media_attachments' | 'spoiler_text' | 'emojis'>;
}
const SensitiveContentOverlay = React.forwardRef<HTMLDivElement, ISensitiveContentOverlay>(({ status }, ref) => {

View file

@ -9,7 +9,7 @@ import { useInstance } from 'bigbuffet/hooks/useInstance';
import Icon from './icon';
import type { Status } from 'bigbuffet/normalizers/status';
import type { UseStatusData as Status } from 'pl-hooks';
interface ITranslateButton {
status: Pick<Status, 'id' | 'account' | 'content' | 'language' | 'translating' | 'translation' | 'visibility'>;
@ -30,7 +30,7 @@ const TranslateButton: React.FC<ITranslateButton> = ({ status }) => {
const renderTranslate = allowUnauthenticated && (allowRemote || status.account.local) && ['public', 'unlisted'].includes(status.visibility) && status.content.trim().length && status.language !== null && intl.locale !== status.language;
const supportsLanguages = (translationLanguages[status.language!]?.includes(intl.locale));
const supportsLanguages = (translationLanguages?.[status.language!]?.includes(intl.locale));
const handleTranslate: React.MouseEventHandler<HTMLButtonElement> = (e) => {
e.stopPropagation();

View file

@ -28,7 +28,7 @@ export const AccountHashtagTimeline: React.FC<IHashtagTimeline> = ({ params }) =
const path = `account:${account?.id}:hashtag:${id}`;
const statusIds = useAppSelector(state => getStatusIds(state, { type: path, prefix: 'account_timeline' }));
const statusIds = useAppSelector(state => getStatusIds(state, { type: path }));
const isLoading = useAppSelector(state => state.timelines.get(path)?.isLoading === true);
const hasMore = useAppSelector(state => state.timelines.get(path)?.hasMore === true);

View file

@ -5,7 +5,7 @@ import Account from 'bigbuffet/components/account';
import Icon from 'bigbuffet/components/icon';
import Emojify from 'bigbuffet/features/emoji';
import type { Account as AccountEntity } from 'bigbuffet/normalizers/account';
import type { UseAccountData as AccountEntity } from 'pl-hooks';
interface IMovedNote {
from: Pick<AccountEntity, 'display_name' | 'emojis'>;

View file

@ -14,7 +14,7 @@ import { useFeatures } from 'bigbuffet/hooks/useFeatures';
import { useModalsStore } from 'bigbuffet/stores/modals';
import { isDefaultHeader } from 'bigbuffet/utils/accounts';
import type { Account } from 'bigbuffet/normalizers/account';
import type { UseAccountData as Account } from 'pl-hooks';
const messages = defineMessages({
header: { id: 'account.header.alt', defaultMessage: 'Profile header' },

View file

@ -6,10 +6,10 @@ import { useFeatures } from 'bigbuffet/hooks/useFeatures';
import { useModalsStore } from 'bigbuffet/stores/modals';
import type { ButtonThemes } from 'bigbuffet/components/ui/button';
import type { Status as StatusEntity } from 'bigbuffet/normalizers/status';
import type { UseStatusData as Status } from 'pl-hooks';
interface IEventAction {
status: Pick<StatusEntity, 'url'>;
status: Pick<Status, 'url'>;
theme?: ButtonThemes;
}

View file

@ -20,7 +20,7 @@ import EventActionButton from '../components/event-action-button';
import EventDate from '../components/event-date';
import type { Menu as MenuType } from 'bigbuffet/components/dropdown-menu';
import type { Status } from 'bigbuffet/normalizers/status';
import type { UseStatusData as Status } from 'pl-hooks';
const messages = defineMessages({
bannerHeader: { id: 'event.banner', defaultMessage: 'Event banner' },

View file

@ -8,6 +8,7 @@ import StatusContent from 'bigbuffet/components/status-content';
import StatusMedia from 'bigbuffet/components/status-media';
import TranslateButton from 'bigbuffet/components/translate-button';
import QuotedStatus from 'bigbuffet/features/status/containers/quoted-status-container';
import { useStatusMetaStore } from 'bigbuffet/stores/status-meta';
type RouteParams = { statusId: string };
@ -100,7 +101,7 @@ const EventInformation: React.FC<IEventInformation> = ({ params: { statusId: sta
}, [status]);
const renderLinks = useCallback(() => {
if (!status.event?.links.length) return null;
if (!status?.event?.links.length) return null;
return (
<div className='event-information__description'>

View file

@ -11,13 +11,13 @@ import QuotedStatus from 'bigbuffet/features/status/containers/quoted-status-con
import StatusInteractionBar from './status-interaction-bar';
import type { SelectedStatus } from 'bigbuffet/selectors';
import type { UseStatusData as Status } from 'pl-hooks';
interface IDetailedStatus {
status: SelectedStatus;
status: Status;
showMedia: boolean;
withMedia?: boolean;
onOpenCompareHistoryModal: (status: Pick<SelectedStatus, 'id'>) => void;
onOpenCompareHistoryModal: (status: Pick<Status, 'id'>) => void;
onToggleMediaVisibility: () => void;
}

View file

@ -8,7 +8,7 @@ import { useFeatures } from 'bigbuffet/hooks/useFeatures';
import { reduceEmoji } from 'bigbuffet/utils/emoji-reacts';
import { shortNumberFormat } from 'bigbuffet/utils/numbers';
import type { Status } from 'bigbuffet/normalizers/status';
import type { UseStatusData as Status } from 'pl-hooks';
interface IStatusInteractionBar {
status: Pick<Status, 'id' | 'account' | 'dislikes_count' | 'emoji_reactions' | 'favourited' | 'favourites_count' | 'reblogs_count' | 'replies_count' | 'quotes_count'>;

View file

@ -19,8 +19,8 @@ import DetailedStatus from './detailed-status';
import ThreadStatus from './thread-status';
import type { Virtualizer } from '@tanstack/react-virtual';
import type { Status } from 'bigbuffet/normalizers/status';
import type { SelectedStatus } from 'bigbuffet/selectors';
// import type { Status } from 'bigbuffet/normalizers/status';
import type { UseStatusData as Status } from 'pl-hooks';
export const getAncestorsIds = createSelector([
(_: RootState, statusId: string | undefined) => statusId,
@ -69,7 +69,7 @@ export const getDescendantsIds = createSelector([
});
interface IThread {
status: SelectedStatus;
status: Status;
withMedia?: boolean;
useWindowScroll?: boolean;
itemClassName?: string;
@ -131,7 +131,7 @@ const Thread: React.FC<IThread> = ({
}
};
const handleToggleHidden = (status: Pick<SelectedStatus, 'id' | 'sensitive'>) => {
const handleToggleHidden = () => {
if (showMedia) {
hideStatus(status.id);
} else {
@ -152,11 +152,11 @@ const Thread: React.FC<IThread> = ({
};
const handleHotkeyToggleHidden = () => {
handleToggleHidden(status!);
handleToggleHidden();
};
const handleHotkeyToggleSensitive = () => {
handleToggleHidden(status!);
handleToggleHidden();
};
const handleMoveUp = (id: string) => {

View file

@ -5,7 +5,7 @@ import Button from 'bigbuffet/components/ui/button';
import { useFeatures } from 'bigbuffet/hooks/useFeatures';
import { useModalsStore } from 'bigbuffet/stores/modals';
import type { Account } from 'bigbuffet/normalizers/account';
import type { UseAccountData as Account } from 'pl-hooks';
const messages = defineMessages({
follow: { id: 'account.follow', defaultMessage: 'Follow' },

View file

@ -7,8 +7,8 @@ import Video from 'bigbuffet/features/video';
import { BaseModalProps } from '../modal-root';
import type { Account } from 'bigbuffet/normalizers/account';
import type { MediaAttachment } from 'pl-api';
import type { UseAccountData as Account } from 'pl-hooks';
interface VideoModalProps {
media: MediaAttachment;

View file

@ -7,7 +7,7 @@ import { ParsedContent } from 'bigbuffet/components/parsed-content';
import Emojify from 'bigbuffet/features/emoji';
import { unescapeHTML } from 'bigbuffet/utils/html';
import type { Account } from 'bigbuffet/normalizers/account';
import type { UseAccountData as Account } from 'pl-hooks';
// const getTicker = (value: string): string => (value.match(/\$([a-zA-Z]*)/i) || [])[1];
// const isTicker = (value: string): boolean => Boolean(getTicker(value));

View file

@ -11,7 +11,7 @@ import { capitalize } from 'bigbuffet/utils/strings';
import ProfileField from './profile-field';
import type { Account } from 'bigbuffet/normalizers/account';
import type { UseAccountData as Account } from 'pl-hooks';
const messages = defineMessages({
linkVerifiedOn: { id: 'account.link_verified_on', defaultMessage: 'Ownership of this link was checked on {date}' },

View file

@ -1,7 +1,7 @@
import { useStatusMetaStore } from 'bigbuffet/stores/status-meta';
import type { SelectedStatus } from 'bigbuffet/selectors';
import type { UseStatusData as Status } from 'pl-hooks';
const useShowMedia = (status: SelectedStatus) => useStatusMetaStore().statuses[status.id]?.visible ?? !status.sensitive;
const useShowMedia = (status: Pick<Status, 'id' | 'sensitive'>) => useStatusMetaStore().statuses[status.id]?.visible ?? !status.sensitive;
export { useShowMedia };

View file

@ -10,6 +10,8 @@ import { unescapeHTML } from 'bigbuffet/utils/html';
import { normalizeAccount } from './account';
import type { UseStatusData } from 'pl-hooks';
const domParser = new DOMParser();
type StatusApprovalStatus = Exclude<BaseStatus['approval_status'], null>;
@ -24,7 +26,7 @@ type CalculatedValues = {
type OldStatus = Pick<BaseStatus, 'content' | 'spoiler_text'> & CalculatedValues;
// Gets titles of poll options from status
const getPollOptionTitles = ({ poll }: Pick<BaseStatus, 'poll'>): readonly string[] => {
const getPollOptionTitles = ({ poll }: Pick<BaseStatus | UseStatusData, 'poll'>): readonly string[] => {
if (poll && typeof poll === 'object') {
return poll.options.map(({ title }) => title);
} else {
@ -37,7 +39,7 @@ const getMentionedUsernames = (status: Pick<BaseStatus, 'mentions'>): Array<stri
status.mentions.map(({ acct }) => `@${acct}`);
// Creates search text from the status
const buildSearchContent = (status: Pick<BaseStatus, 'poll' | 'mentions' | 'spoiler_text' | 'content'>): string => {
const buildSearchContent = (status: Pick<BaseStatus | UseStatusData, 'poll' | 'mentions' | 'spoiler_text' | 'content'>): string => {
const pollOptionTitles = getPollOptionTitles(status);
const mentionedUsernames = getMentionedUsernames(status);
@ -149,8 +151,9 @@ const normalizeStatus = (status: BaseStatus & {
type Status = ReturnType<typeof normalizeStatus>;
export {
type Status,
type StatusApprovalStatus,
type StatusVisibility,
buildSearchContent,
normalizeStatus,
type Status,
};

View file

@ -1,10 +1,10 @@
import { create } from 'zustand';
type State = {
ref: React.MutableRefObject<HTMLDivElement> | null;
ref: React.MutableRefObject<HTMLDivElement | null> | null;
accountId: string | null;
hovered: boolean;
openAccountHoverCard: (ref: React.MutableRefObject<HTMLDivElement>, accountId: string) => void;
openAccountHoverCard: (ref: React.MutableRefObject<HTMLDivElement | null>, accountId: string) => void;
updateAccountHoverCard: () => void;
closeAccountHoverCard: (force?: boolean) => void;
}

View file

@ -1,10 +1,10 @@
import { create } from 'zustand';
type State = {
ref: React.MutableRefObject<HTMLDivElement> | null;
ref: React.MutableRefObject<HTMLDivElement | null> | null;
statusId: string | null;
hovered: boolean;
openStatusHoverCard: (ref: React.MutableRefObject<HTMLDivElement>, statusId: string) => void;
openStatusHoverCard: (ref: React.MutableRefObject<HTMLDivElement | null>, statusId: string) => void;
updateStatusHoverCard: () => void;
closeStatusHoverCard: (force?: boolean) => void;
}

View file

@ -1,4 +1,4 @@
import type { Account } from 'bigbuffet/normalizers/account';
import type { UseAccountData as Account } from 'pl-hooks';
const getAcct = (account: Pick<Account, 'fqn' | 'acct'>, displayFqn: boolean): string =>
(displayFqn === true && account.fqn) || account.acct;

View file

@ -1,4 +1,4 @@
import type { Account } from 'bigbuffet/normalizers/account';
import type { UseAccountData as Account } from 'pl-hooks';
/** Convert a badge into a plain tag. */
const badgeToTag = (badge: string) => badge.replace(/^badge:/, '');

View file

@ -1,10 +1,12 @@
import type { Status } from 'bigbuffet/normalizers/status';
import { buildSearchContent } from 'bigbuffet/normalizers/status';
import type { UseStatusData as Status } from 'pl-hooks';
import type { IntlShape } from 'react-intl';
/** Sanitize status text for use with screen readers. */
const textForScreenReader = (
intl: IntlShape,
status: Pick<Status, 'account' | 'spoiler_text' | 'search_index' | 'created_at'>,
status: Pick<Status, 'account' | 'content' | 'created_at' | 'mentions' | 'poll' | 'spoiler_text'>,
rebloggedByText?: string,
): string => {
const { account } = status;
@ -14,7 +16,8 @@ const textForScreenReader = (
const values = [
displayName.length === 0 ? account.acct.split('@')[0] : displayName,
status.search_index?.slice(status.spoiler_text.length),
buildSearchContent(status),
// status.search_index?.slice(status.spoiler_text.length),
intl.formatDate(status.created_at, { hour: '2-digit', minute: '2-digit', month: 'short', day: 'numeric' }),
account.acct,
];