mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 13:05:32 +09:00
feat(expressions): remove the unfinished packs feature (#2250)
This commit is contained in:
1 parent
0eef611b6d
commit
b8f8d8d859
159 files changed
+42
-6863
No files matched your search
@@ -4,7 +4,6 @@ import {DesktopSettingsView} from '@app/features/app/components/dialogs/componen
|
||||
import {MobileSettingsView} from '@app/features/app/components/dialogs/components/MobileSettingsView';
|
||||
import * as Modal from '@app/features/app/components/dialogs/Modal';
|
||||
import {SettingsModalContainer} from '@app/features/app/components/dialogs/shared/SettingsModalLayout';
|
||||
import DeveloperOptions from '@app/features/devtools/state/DeveloperOptions';
|
||||
import {ComponentBus} from '@app/features/platform/utils/ComponentBus';
|
||||
import * as ModalCommands from '@app/features/ui/commands/ModalCommands';
|
||||
import * as UnsavedChangesCommands from '@app/features/ui/commands/UnsavedChangesCommands';
|
||||
@@ -24,7 +23,6 @@ import type {UserSettingsTabType} from '@app/features/user/components/settings_u
|
||||
import {useMobileNavigation} from '@app/features/user/hooks/useMobileNavigation';
|
||||
import {SettingsContentKeyProvider} from '@app/features/user/hooks/useSettingsContentKey';
|
||||
import UserSettings from '@app/features/user/state/UserSettings';
|
||||
import Users from '@app/features/user/state/Users';
|
||||
import {useLingui} from '@lingui/react/macro';
|
||||
import {observer} from 'mobx-react-lite';
|
||||
import type React from 'react';
|
||||
@@ -45,20 +43,15 @@ export const UserSettingsModal: React.FC<UserSettingsModalProps> = observer(
|
||||
getAccountSectionForNestedTab(initialTab) ?? getAccountSectionForLegacySection(initialSubtab);
|
||||
const normalizedInitialTab = initialAccountSection ? ACCOUNT_SETTINGS_TAB : initialTab;
|
||||
const normalizedInitialSubtab = initialAccountSection ?? initialSubtab;
|
||||
const isStaff = Users.getCurrentUser()?.isStaff() ?? false;
|
||||
const hasExpressionPackAccess = isStaff && DeveloperOptions.showExpressionPacksSettings;
|
||||
const isDeveloperModeEnabled = UserSettings.developerMode;
|
||||
const visibleSettingsTabs = useMemo(() => {
|
||||
return settingsTabs.filter((tab) => {
|
||||
if (!hasExpressionPackAccess && tab.type === 'expression_packs') {
|
||||
return false;
|
||||
}
|
||||
if (!isDeveloperModeEnabled && (tab.type === 'embed_debugger' || tab.type === 'component_gallery')) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}, [hasExpressionPackAccess, isDeveloperModeEnabled, settingsTabs]);
|
||||
}, [isDeveloperModeEnabled, settingsTabs]);
|
||||
const resolveVisibleTab = useCallback(
|
||||
(tabType?: UserSettingsTabType): UserSettingsTabType => {
|
||||
if (tabType && visibleSettingsTabs.some((tab) => tab.type === tabType)) {
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
/* SPDX-License-Identifier: AGPL-3.0-or-later */
|
||||
|
||||
.emptyState {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.spinnerWrapper {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.sectionActions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.section {
|
||||
background: var(--form-surface-background);
|
||||
border: 0.0625rem solid var(--background-modifier-selected);
|
||||
border-radius: var(--radius-xl);
|
||||
margin-bottom: var(--spacing-6);
|
||||
padding: var(--spacing-5);
|
||||
}
|
||||
|
||||
.sectionHeader {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.sectionTitle {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.sectionSubtitle {
|
||||
color: var(--text-secondary);
|
||||
font-size: 0.875rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.listWrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-3);
|
||||
margin-top: var(--spacing-3);
|
||||
}
|
||||
|
||||
.emptyText {
|
||||
color: var(--text-tertiary);
|
||||
font-size: 0.875rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.packCard {
|
||||
background: var(--background-secondary);
|
||||
border: 0.0625rem solid var(--background-modifier-selected);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--spacing-4);
|
||||
}
|
||||
|
||||
.packCardHeader {
|
||||
align-items: baseline;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: var(--spacing-2);
|
||||
}
|
||||
|
||||
.packName {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.packMeta {
|
||||
color: var(--text-tertiary);
|
||||
font-size: 0.75rem;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.packDescription {
|
||||
color: var(--text-secondary);
|
||||
font-size: 0.875rem;
|
||||
margin: 0 0 var(--spacing-3);
|
||||
}
|
||||
|
||||
.packTimestamp {
|
||||
color: var(--text-tertiary);
|
||||
font-size: 0.75rem;
|
||||
margin: 0 0 var(--spacing-3);
|
||||
}
|
||||
|
||||
.cardActions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--spacing-2);
|
||||
justify-content: flex-end;
|
||||
}
|
||||
@@ -1,366 +0,0 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import {ConfirmModal} from '@app/features/app/components/dialogs/ConfirmModal';
|
||||
import {SettingsSection} from '@app/features/app/components/dialogs/shared/SettingsSection';
|
||||
import {SettingsTabContainer, SettingsTabSection} from '@app/features/app/components/dialogs/shared/SettingsTabLayout';
|
||||
import {StatusSlate} from '@app/features/app/components/dialogs/shared/StatusSlate';
|
||||
import {PREMIUM_PRODUCT_FULL_NAME, PREMIUM_PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstants';
|
||||
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
|
||||
import {LimitResolver} from '@app/features/app/utils/LimitResolverAdapter';
|
||||
import {isLimitToggleEnabled} from '@app/features/app/utils/LimitUtils';
|
||||
import {CreatePackModal} from '@app/features/expressions/components/modals/CreatePackModal';
|
||||
import {EditPackModal} from '@app/features/expressions/components/modals/EditPackModal';
|
||||
import {PackInviteModal} from '@app/features/expressions/components/modals/PackInviteModal';
|
||||
import Packs from '@app/features/expressions/state/ExpressionsPacks';
|
||||
import {NO_DESCRIPTION_PROVIDED_DESCRIPTOR} from '@app/features/i18n/utils/CommonMessageDescriptors';
|
||||
import {ComponentBus} from '@app/features/platform/utils/ComponentBus';
|
||||
import {Button} from '@app/features/ui/button/Button';
|
||||
import * as ModalCommands from '@app/features/ui/commands/ModalCommands';
|
||||
import {modal} from '@app/features/ui/commands/ModalCommands';
|
||||
import {Spinner} from '@app/features/ui/components/Spinner';
|
||||
import styles from '@app/features/user/components/modals/tabs/ExpressionPacksTab.module.css';
|
||||
import Users from '@app/features/user/state/Users';
|
||||
import {getFormattedShortDate} from '@app/features/user/utils/DateFormatting';
|
||||
import type {PackSummaryResponse} from '@fluxer/schema/src/domains/pack/PackSchemas';
|
||||
import {msg} from '@lingui/core/macro';
|
||||
import {Trans, useLingui} from '@lingui/react/macro';
|
||||
import {StickerIcon} from '@phosphor-icons/react';
|
||||
import {observer} from 'mobx-react-lite';
|
||||
import type React from 'react';
|
||||
import {useEffect, useMemo, useState} from 'react';
|
||||
|
||||
const UNLIMITED_DESCRIPTOR = msg({
|
||||
message: 'Unlimited',
|
||||
comment: 'Short label in the expression packs tab. Keep it concise.',
|
||||
});
|
||||
const UNABLE_TO_LOAD_PACK_INFORMATION_DESCRIPTOR = msg({
|
||||
message: 'Unable to load pack information.',
|
||||
comment: 'Error message in the expression packs tab.',
|
||||
});
|
||||
const DELETE_PACK_DESCRIPTOR = msg({
|
||||
message: 'Delete pack',
|
||||
comment:
|
||||
'Button or menu action label in the expression packs tab. Keep it concise. Keep the tone plain and specific.',
|
||||
});
|
||||
const ARE_YOU_SURE_YOU_WANT_TO_DELETE_THIS_DESCRIPTOR = msg({
|
||||
message: "Delete this pack? Can't be undone.",
|
||||
comment: 'Error message in the expression packs tab. Keep the tone plain and specific.',
|
||||
});
|
||||
const DELETE_DESCRIPTOR = msg({
|
||||
message: 'Delete',
|
||||
comment:
|
||||
'Button or menu action label in the expression packs tab. Keep it concise. Keep the tone plain and specific.',
|
||||
});
|
||||
const REMOVE_PACK_DESCRIPTOR = msg({
|
||||
message: 'Remove pack',
|
||||
comment:
|
||||
'Button or menu action label in the expression packs tab. Keep it concise. Keep the tone plain and specific.',
|
||||
});
|
||||
const EXPRESSION_PACKS_PREMIUM_FEATURE_DESCRIPTOR = msg({
|
||||
message: 'Expression packs are a {premiumProductName} feature',
|
||||
comment: 'Empty-state title for expression packs when the feature requires premium.',
|
||||
});
|
||||
const PREMIUM_EXPRESSION_PACKS_DESCRIPTION_DESCRIPTOR = msg({
|
||||
message: 'Create and share custom emoji and sticker packs with {premiumProductFullName}.',
|
||||
comment: 'Empty-state description for expression packs when the feature requires premium.',
|
||||
});
|
||||
const LEARN_ABOUT_PREMIUM_DESCRIPTOR = msg({
|
||||
message: 'Learn about {premiumProductName}',
|
||||
comment: 'CTA label that opens the premium settings tab from expression packs.',
|
||||
});
|
||||
const REMOVING_THE_PACK_WILL_UNINSTALL_IT_FROM_YOUR_DESCRIPTOR = msg({
|
||||
message: 'Removing the pack will uninstall it from your account.',
|
||||
comment: 'Description text in the expression packs tab.',
|
||||
});
|
||||
const REMOVE_DESCRIPTOR = msg({
|
||||
message: 'Remove',
|
||||
comment:
|
||||
'Button or menu action label in the expression packs tab. Keep it concise. Keep the tone plain and specific.',
|
||||
});
|
||||
const EMOJI_PACKS_DESCRIPTOR = msg({
|
||||
message: 'Emoji packs',
|
||||
comment: 'Short label in the expression packs tab. Keep it concise.',
|
||||
});
|
||||
const STICKER_PACKS_DESCRIPTOR = msg({
|
||||
message: 'Sticker packs',
|
||||
comment: 'Short label in the expression packs tab. Keep it concise.',
|
||||
});
|
||||
const PACK_TYPES: Array<{key: 'emoji' | 'sticker'}> = [{key: 'emoji'}, {key: 'sticker'}];
|
||||
const PackCard: React.FC<{
|
||||
pack: PackSummaryResponse;
|
||||
onUninstall?: () => void;
|
||||
onEdit?: () => void;
|
||||
onInvite?: () => void;
|
||||
created?: boolean;
|
||||
}> = observer(({pack, onUninstall, onEdit, onInvite, created}) => {
|
||||
const {i18n} = useLingui();
|
||||
const installedAt = pack.installed_at ? getFormattedShortDate(new Date(pack.installed_at)) : null;
|
||||
return (
|
||||
<div className={styles.packCard} data-flx="user.expression-packs-tab.pack-card.pack-card">
|
||||
<div className={styles.packCardHeader} data-flx="user.expression-packs-tab.pack-card.pack-card-header">
|
||||
<h3 className={styles.packName} data-flx="user.expression-packs-tab.pack-card.pack-name">
|
||||
{pack.name}
|
||||
</h3>
|
||||
<span className={styles.packMeta} data-flx="user.expression-packs-tab.pack-card.pack-meta">
|
||||
{pack.type === 'emoji' ? <Trans>Emoji pack</Trans> : <Trans>Sticker pack</Trans>}
|
||||
</span>
|
||||
</div>
|
||||
<p className={styles.packDescription} data-flx="user.expression-packs-tab.pack-card.pack-description">
|
||||
{pack.description || i18n._(NO_DESCRIPTION_PROVIDED_DESCRIPTOR)}
|
||||
</p>
|
||||
{installedAt && (
|
||||
<p className={styles.packTimestamp} data-flx="user.expression-packs-tab.pack-card.pack-timestamp">
|
||||
<Trans>Installed on {installedAt}</Trans>
|
||||
</p>
|
||||
)}
|
||||
<div className={styles.cardActions} data-flx="user.expression-packs-tab.pack-card.card-actions">
|
||||
{created && (
|
||||
<>
|
||||
<Button variant="secondary" onClick={onInvite} data-flx="user.expression-packs-tab.pack-card.button.invite">
|
||||
<Trans>Invite</Trans>
|
||||
</Button>
|
||||
<Button variant="secondary" onClick={onEdit} data-flx="user.expression-packs-tab.pack-card.button.edit">
|
||||
<Trans>Edit</Trans>
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
{onUninstall && (
|
||||
<Button
|
||||
variant="danger"
|
||||
onClick={onUninstall}
|
||||
data-flx="user.expression-packs-tab.pack-card.button.uninstall"
|
||||
>
|
||||
<Trans>Remove</Trans>
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
const ExpressionPacksTab: React.FC = observer(() => {
|
||||
const {i18n} = useLingui();
|
||||
const formatLimit = (value: number): string => {
|
||||
if (value === Number.POSITIVE_INFINITY) return i18n._(UNLIMITED_DESCRIPTOR);
|
||||
return value.toString();
|
||||
};
|
||||
const currentUser = Users.currentUser;
|
||||
const hasGlobalExpressions = useMemo(
|
||||
() =>
|
||||
isLimitToggleEnabled(
|
||||
{feature_global_expressions: LimitResolver.resolve({key: 'feature_global_expressions', fallback: 0})},
|
||||
'feature_global_expressions',
|
||||
),
|
||||
[],
|
||||
);
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
useEffect(() => {
|
||||
if (!hasGlobalExpressions || loaded) return;
|
||||
Packs.fetch().finally(() => setLoaded(true));
|
||||
}, [hasGlobalExpressions, loaded]);
|
||||
if (!currentUser) return null;
|
||||
if (!hasGlobalExpressions && RuntimeConfig.isSelfHosted()) {
|
||||
return (
|
||||
<div className={styles.emptyState} data-flx="user.expression-packs-tab.empty-state">
|
||||
<StatusSlate
|
||||
Icon={StickerIcon}
|
||||
title={<Trans>Expression packs</Trans>}
|
||||
description={
|
||||
<Trans>
|
||||
Expression packs are not enabled on this instance. Contact your instance administrator for more
|
||||
information.
|
||||
</Trans>
|
||||
}
|
||||
data-flx="user.expression-packs-tab.status-slate"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (!hasGlobalExpressions) {
|
||||
return (
|
||||
<div className={styles.emptyState} data-flx="user.expression-packs-tab.empty-state--2">
|
||||
<StatusSlate
|
||||
Icon={StickerIcon}
|
||||
title={i18n._(EXPRESSION_PACKS_PREMIUM_FEATURE_DESCRIPTOR, {
|
||||
premiumProductName: PREMIUM_PRODUCT_NAME,
|
||||
})}
|
||||
description={i18n._(PREMIUM_EXPRESSION_PACKS_DESCRIPTION_DESCRIPTOR, {
|
||||
premiumProductFullName: PREMIUM_PRODUCT_FULL_NAME,
|
||||
})}
|
||||
actions={[
|
||||
{
|
||||
text: i18n._(LEARN_ABOUT_PREMIUM_DESCRIPTOR, {premiumProductName: PREMIUM_PRODUCT_NAME}),
|
||||
onClick: () => ComponentBus.dispatch('USER_SETTINGS_TAB_SELECT', {tab: 'plutonium'}),
|
||||
variant: 'primary',
|
||||
fitContent: true,
|
||||
},
|
||||
]}
|
||||
data-flx="user.expression-packs-tab.status-slate--2"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
const dashboard = Packs.dashboard;
|
||||
const fetchStatus = Packs.fetchStatus;
|
||||
if (fetchStatus === 'pending') {
|
||||
return (
|
||||
<div className={styles.spinnerWrapper} data-flx="user.expression-packs-tab.spinner-wrapper">
|
||||
<Spinner data-flx="user.expression-packs-tab.spinner" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (!dashboard) {
|
||||
return (
|
||||
<div className={styles.emptyState} data-flx="user.expression-packs-tab.empty-state--3">
|
||||
<p data-flx="user.expression-packs-tab.p">{i18n._(UNABLE_TO_LOAD_PACK_INFORMATION_DESCRIPTOR)}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
const handleOpenCreate = (type: 'emoji' | 'sticker') => {
|
||||
ModalCommands.push(
|
||||
modal(() => (
|
||||
<CreatePackModal
|
||||
type={type}
|
||||
onSuccess={() => Packs.fetch()}
|
||||
data-flx="user.expression-packs-tab.handle-open-create.create-pack-modal"
|
||||
/>
|
||||
)),
|
||||
);
|
||||
};
|
||||
const handleOpenEdit = (pack: PackSummaryResponse) => {
|
||||
ModalCommands.push(
|
||||
modal(() => (
|
||||
<EditPackModal
|
||||
packId={pack.id}
|
||||
type={pack.type}
|
||||
name={pack.name}
|
||||
description={pack.description}
|
||||
onSuccess={() => Packs.fetch()}
|
||||
data-flx="user.expression-packs-tab.handle-open-edit.edit-pack-modal"
|
||||
/>
|
||||
)),
|
||||
);
|
||||
};
|
||||
const handleOpenInvite = (pack: PackSummaryResponse) => {
|
||||
ModalCommands.push(
|
||||
modal(() => (
|
||||
<PackInviteModal
|
||||
packId={pack.id}
|
||||
type={pack.type}
|
||||
onCreated={() => Packs.fetch()}
|
||||
data-flx="user.expression-packs-tab.handle-open-invite.pack-invite-modal"
|
||||
/>
|
||||
)),
|
||||
);
|
||||
};
|
||||
const handleDelete = (packId: string) => {
|
||||
ModalCommands.push(
|
||||
modal(() => (
|
||||
<ConfirmModal
|
||||
title={i18n._(DELETE_PACK_DESCRIPTOR)}
|
||||
description={i18n._(ARE_YOU_SURE_YOU_WANT_TO_DELETE_THIS_DESCRIPTOR)}
|
||||
primaryText={i18n._(DELETE_DESCRIPTOR)}
|
||||
primaryVariant="danger"
|
||||
onPrimary={async () => {
|
||||
await Packs.deletePack(packId);
|
||||
}}
|
||||
data-flx="user.expression-packs-tab.handle-delete.confirm-modal"
|
||||
/>
|
||||
)),
|
||||
);
|
||||
};
|
||||
const handleUninstall = (packId: string) => {
|
||||
ModalCommands.push(
|
||||
modal(() => (
|
||||
<ConfirmModal
|
||||
title={i18n._(REMOVE_PACK_DESCRIPTOR)}
|
||||
description={i18n._(REMOVING_THE_PACK_WILL_UNINSTALL_IT_FROM_YOUR_DESCRIPTOR)}
|
||||
primaryText={i18n._(REMOVE_DESCRIPTOR)}
|
||||
onPrimary={async () => {
|
||||
await Packs.uninstallPack(packId);
|
||||
}}
|
||||
data-flx="user.expression-packs-tab.handle-uninstall.confirm-modal"
|
||||
/>
|
||||
)),
|
||||
);
|
||||
};
|
||||
return (
|
||||
<SettingsTabContainer data-flx="user.expression-packs-tab.settings-tab-container">
|
||||
{PACK_TYPES.map((section) => {
|
||||
const data = section.key === 'emoji' ? dashboard.emoji : dashboard.sticker;
|
||||
const sectionId = section.key === 'emoji' ? 'emoji-packs' : 'sticker-packs';
|
||||
const sectionLabel =
|
||||
section.key === 'emoji' ? i18n._(EMOJI_PACKS_DESCRIPTOR) : i18n._(STICKER_PACKS_DESCRIPTOR);
|
||||
const installedCount = data.installed.length;
|
||||
const installedLimit = formatLimit(data.installed_limit);
|
||||
const createdCount = data.created.length;
|
||||
const createdLimit = formatLimit(data.created_limit);
|
||||
return (
|
||||
<SettingsSection
|
||||
key={section.key}
|
||||
id={sectionId}
|
||||
title={sectionLabel}
|
||||
description={
|
||||
<Trans>
|
||||
Installed {installedCount} / {installedLimit}
|
||||
</Trans>
|
||||
}
|
||||
data-flx="user.expression-packs-tab.section"
|
||||
>
|
||||
<div className={styles.sectionActions} data-flx="user.expression-packs-tab.section-actions">
|
||||
<Button
|
||||
onClick={() => handleOpenCreate(section.key)}
|
||||
data-flx="user.expression-packs-tab.button.open-create"
|
||||
>
|
||||
{section.key === 'emoji' ? <Trans>Create emoji pack</Trans> : <Trans>Create sticker pack</Trans>}
|
||||
</Button>
|
||||
</div>
|
||||
<div className={styles.listWrapper} data-flx="user.expression-packs-tab.list-wrapper">
|
||||
{data.installed.length === 0 && (
|
||||
<p className={styles.emptyText} data-flx="user.expression-packs-tab.empty-text">
|
||||
<Trans>No installed packs yet.</Trans>
|
||||
</p>
|
||||
)}
|
||||
{data.installed.map((pack) => (
|
||||
<PackCard
|
||||
key={pack.id}
|
||||
pack={pack}
|
||||
onUninstall={() => handleUninstall(pack.id)}
|
||||
data-flx="user.expression-packs-tab.pack-card"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<SettingsTabSection
|
||||
title={
|
||||
<Trans>
|
||||
Created {createdCount} / {createdLimit}
|
||||
</Trans>
|
||||
}
|
||||
data-flx="user.expression-packs-tab.created-section"
|
||||
>
|
||||
<div className={styles.listWrapper} data-flx="user.expression-packs-tab.list-wrapper--2">
|
||||
{data.created.length === 0 && (
|
||||
<p className={styles.emptyText} data-flx="user.expression-packs-tab.empty-text--2">
|
||||
<Trans>You haven't created any packs yet.</Trans>
|
||||
</p>
|
||||
)}
|
||||
{data.created.map((pack) => (
|
||||
<PackCard
|
||||
key={pack.id}
|
||||
pack={pack}
|
||||
created={true}
|
||||
onInvite={() => handleOpenInvite(pack)}
|
||||
onEdit={() => handleOpenEdit(pack)}
|
||||
onUninstall={() => handleDelete(pack.id)}
|
||||
data-flx="user.expression-packs-tab.pack-card--2"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</SettingsTabSection>
|
||||
</SettingsSection>
|
||||
);
|
||||
})}
|
||||
</SettingsTabContainer>
|
||||
);
|
||||
});
|
||||
|
||||
export default ExpressionPacksTab;
|
||||
-1
@@ -52,7 +52,6 @@ const SOURCE_TAB_CATEGORY: Partial<Record<UserSettingsTabType, SettingsCategoryT
|
||||
linked_accounts: 'account',
|
||||
plutonium: 'account',
|
||||
gift_inventory: 'account',
|
||||
expression_packs: 'account',
|
||||
privacy_safety: 'privacy',
|
||||
authorized_apps: 'privacy',
|
||||
blocked_users: 'privacy',
|
||||
|
||||
@@ -9,7 +9,6 @@ import ChatSettingsTab from '@app/features/user/components/modals/tabs/ChatSetti
|
||||
import ComponentGalleryTab from '@app/features/user/components/modals/tabs/component_gallery_tab';
|
||||
import DesktopSettingsTab from '@app/features/user/components/modals/tabs/DesktopSettingsTab';
|
||||
import EmbedDebuggerTab from '@app/features/user/components/modals/tabs/EmbedDebuggerTab';
|
||||
import ExpressionPacksTab from '@app/features/user/components/modals/tabs/ExpressionPacksTab';
|
||||
import GiftInventoryTab from '@app/features/user/components/modals/tabs/GiftInventoryTab';
|
||||
import KeybindsTab from '@app/features/user/components/modals/tabs/KeybindsTab';
|
||||
import LanguageTab from '@app/features/user/components/modals/tabs/LanguageTab';
|
||||
@@ -44,7 +43,6 @@ const DESKTOP_TAB_COMPONENTS: Partial<Record<UserSettingsTabType, React.Componen
|
||||
embed_debugger: EmbedDebuggerTab,
|
||||
applications: ApplicationsTab,
|
||||
component_gallery: ComponentGalleryTab,
|
||||
expression_packs: ExpressionPacksTab,
|
||||
};
|
||||
export const getSettingsTabComponent = (
|
||||
tabType: UserSettingsTabType,
|
||||
|
||||
@@ -44,17 +44,12 @@ import {
|
||||
ProhibitIcon,
|
||||
RobotIcon,
|
||||
ShieldIcon,
|
||||
StickerIcon,
|
||||
TranslateIcon,
|
||||
UserIcon,
|
||||
UserListIcon,
|
||||
} from '@phosphor-icons/react';
|
||||
import type React from 'react';
|
||||
|
||||
const EXPRESSION_PACKS_DESCRIPTOR = msg({
|
||||
message: 'Expression packs',
|
||||
comment: 'User settings tab for purchased or owned emoji/sticker expression packs.',
|
||||
});
|
||||
const BLOCKED_USERS_DESCRIPTOR = msg({
|
||||
message: 'Blocked users',
|
||||
comment: 'User settings tab listing accounts the current user has blocked.',
|
||||
@@ -267,12 +262,6 @@ const ALL_TABS_DESCRIPTORS: Array<SettingsTabDescriptor> = [
|
||||
label: GIFTS_AND_CODES_DESCRIPTOR,
|
||||
icon: GiftIcon,
|
||||
},
|
||||
{
|
||||
type: 'expression_packs',
|
||||
category: 'billing',
|
||||
label: EXPRESSION_PACKS_DESCRIPTOR,
|
||||
icon: StickerIcon,
|
||||
},
|
||||
{
|
||||
type: 'appearance',
|
||||
category: 'app_settings',
|
||||
|
||||
@@ -31,7 +31,6 @@ import {clientDeveloperSettingsIndex} from '@app/features/user/components/settin
|
||||
import {desktopSettingsIndex} from '@app/features/user/components/settings_utils/search_index/DesktopSettingsIndex';
|
||||
import {devicesIndex} from '@app/features/user/components/settings_utils/search_index/DevicesIndex';
|
||||
import {embedDebuggerIndex} from '@app/features/user/components/settings_utils/search_index/EmbedDebuggerIndex';
|
||||
import {expressionPacksIndex} from '@app/features/user/components/settings_utils/search_index/ExpressionPacksIndex';
|
||||
import {giftInventoryIndex} from '@app/features/user/components/settings_utils/search_index/GiftInventoryIndex';
|
||||
import {keybindsIndex} from '@app/features/user/components/settings_utils/search_index/KeybindsIndex';
|
||||
import {languageIndex} from '@app/features/user/components/settings_utils/search_index/LanguageIndex';
|
||||
@@ -100,7 +99,6 @@ const ADDITIONAL_SEARCHABLE_ITEMS: Array<SearchableSettingDescriptor> = [
|
||||
...devicesIndex,
|
||||
...plutoniumIndex,
|
||||
...giftInventoryIndex,
|
||||
...expressionPacksIndex,
|
||||
...appearanceIndex,
|
||||
...notificationsIndex,
|
||||
...chatSettingsIndex,
|
||||
|
||||
@@ -38,7 +38,6 @@ const USER_SETTINGS_TAB_TYPES = new Set<UserSettingsTabType>([
|
||||
'component_gallery',
|
||||
'language',
|
||||
'keybinds',
|
||||
'expression_packs',
|
||||
'linked_accounts',
|
||||
]);
|
||||
const SAFE_SETTINGS_PARAM_REGEX = /^[A-Za-z0-9_-]+$/;
|
||||
|
||||
-70
@@ -1,70 +0,0 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import {STICKERS_DESCRIPTOR} from '@app/features/i18n/utils/CommonMessageDescriptors';
|
||||
import type {SearchableSettingDescriptor} from '@app/features/user/components/settings_utils/search_index/SearchIndexTypes';
|
||||
import {msg} from '@lingui/core/macro';
|
||||
|
||||
const EXPRESSION_PACKS_DESCRIPTOR = msg({
|
||||
message: 'Expression packs',
|
||||
comment: 'Settings search entry label. Names the settings search entry in the settings UI.',
|
||||
});
|
||||
const EMOJI_DESCRIPTOR = msg({
|
||||
message: 'Emoji',
|
||||
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
|
||||
});
|
||||
const PACKS_DESCRIPTOR = msg({
|
||||
message: 'Packs',
|
||||
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
|
||||
});
|
||||
const EXPRESSIONS_DESCRIPTOR = msg({
|
||||
message: 'Expressions',
|
||||
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
|
||||
});
|
||||
const EMOJI_PACKS_DESCRIPTOR = msg({
|
||||
message: 'Emoji packs',
|
||||
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
|
||||
});
|
||||
const STICKER_PACKS_DESCRIPTOR = msg({
|
||||
message: 'Sticker packs',
|
||||
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
|
||||
});
|
||||
const CREATE_EMOJI_PACK_DESCRIPTOR = msg({
|
||||
message: 'Create emoji pack',
|
||||
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
|
||||
});
|
||||
const CREATE_STICKER_PACK_DESCRIPTOR = msg({
|
||||
message: 'Create sticker pack',
|
||||
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
|
||||
});
|
||||
const INSTALLED_PACKS_DESCRIPTOR = msg({
|
||||
message: 'Installed packs',
|
||||
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
|
||||
});
|
||||
const CREATED_PACKS_DESCRIPTOR = msg({
|
||||
message: 'Created packs',
|
||||
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
|
||||
});
|
||||
const MANAGE_EXPRESSION_PACKS_DESCRIPTOR = msg({
|
||||
message: 'Manage expression packs',
|
||||
comment: 'Settings search entry description. One-line summary of what the settings search entry controls.',
|
||||
});
|
||||
export const expressionPacksIndex: Array<SearchableSettingDescriptor> = [
|
||||
{
|
||||
id: 'expression-packs',
|
||||
tabType: 'expression_packs',
|
||||
label: EXPRESSION_PACKS_DESCRIPTOR,
|
||||
keywords: [
|
||||
STICKERS_DESCRIPTOR,
|
||||
EMOJI_DESCRIPTOR,
|
||||
PACKS_DESCRIPTOR,
|
||||
EXPRESSIONS_DESCRIPTOR,
|
||||
EMOJI_PACKS_DESCRIPTOR,
|
||||
STICKER_PACKS_DESCRIPTOR,
|
||||
CREATE_EMOJI_PACK_DESCRIPTOR,
|
||||
CREATE_STICKER_PACK_DESCRIPTOR,
|
||||
INSTALLED_PACKS_DESCRIPTOR,
|
||||
CREATED_PACKS_DESCRIPTOR,
|
||||
],
|
||||
description: MANAGE_EXPRESSION_PACKS_DESCRIPTOR,
|
||||
},
|
||||
];
|
||||
-10
@@ -15,14 +15,6 @@ const PURCHASED_GIFTS_DESCRIPTOR = msg({
|
||||
message: 'Purchased gifts',
|
||||
comment: 'Settings section label for managing purchased gift codes.',
|
||||
});
|
||||
const EMOJI_PACKS_DESCRIPTOR = msg({
|
||||
message: 'Emoji packs',
|
||||
comment: 'Settings section label for emoji expression packs.',
|
||||
});
|
||||
const STICKER_PACKS_DESCRIPTOR = msg({
|
||||
message: 'Sticker packs',
|
||||
comment: 'Settings section label for sticker expression packs.',
|
||||
});
|
||||
const BLOCKED_USERS_DESCRIPTOR = msg({
|
||||
message: 'Blocked users',
|
||||
comment: 'Settings section label for blocked users.',
|
||||
@@ -92,8 +84,6 @@ export const generalSettingsSections = [
|
||||
keywords: [],
|
||||
isAdvanced: false,
|
||||
},
|
||||
{id: 'emoji-packs', tabType: 'expression_packs', label: EMOJI_PACKS_DESCRIPTOR, keywords: [], isAdvanced: false},
|
||||
{id: 'sticker-packs', tabType: 'expression_packs', label: STICKER_PACKS_DESCRIPTOR, keywords: [], isAdvanced: false},
|
||||
{id: 'blocked-users', tabType: 'blocked_users', label: BLOCKED_USERS_DESCRIPTOR, keywords: [], isAdvanced: false},
|
||||
{
|
||||
id: 'authorized-applications',
|
||||
|
||||
-1
@@ -32,7 +32,6 @@ export type UserSettingsTabType =
|
||||
| 'component_gallery'
|
||||
| 'language'
|
||||
| 'keybinds'
|
||||
| 'expression_packs'
|
||||
| 'linked_accounts';
|
||||
|
||||
export interface SectionDefinition extends SettingsMetadata {
|
||||
|
||||
Reference in new issue
Block a user