feat(nagbar): add invite CTA to Fluxer HQ (#68)
This commit is contained in:
parent
288477a5b3
commit
a61b5802f3
@ -28,9 +28,17 @@ interface NagbarButtonProps {
|
||||
isMobile: boolean;
|
||||
className?: string;
|
||||
disabled?: boolean;
|
||||
submitting?: boolean;
|
||||
}
|
||||
|
||||
export const NagbarButton = ({children, onClick, isMobile, className, disabled = false}: NagbarButtonProps) => {
|
||||
export const NagbarButton = ({
|
||||
children,
|
||||
onClick,
|
||||
isMobile,
|
||||
className,
|
||||
disabled = false,
|
||||
submitting,
|
||||
}: NagbarButtonProps) => {
|
||||
return (
|
||||
<Button
|
||||
variant="inverted-outline"
|
||||
@ -40,6 +48,7 @@ export const NagbarButton = ({children, onClick, isMobile, className, disabled =
|
||||
className={clsx(styles.button, className)}
|
||||
onClick={onClick}
|
||||
disabled={disabled}
|
||||
submitting={submitting}
|
||||
>
|
||||
{children}
|
||||
</Button>
|
||||
|
||||
@ -25,6 +25,7 @@ import {DesktopDownloadNagbar} from './nagbars/DesktopDownloadNagbar';
|
||||
import {DesktopNotificationNagbar} from './nagbars/DesktopNotificationNagbar';
|
||||
import {EmailVerificationNagbar} from './nagbars/EmailVerificationNagbar';
|
||||
import {GiftInventoryNagbar} from './nagbars/GiftInventoryNagbar';
|
||||
import {GuildMembershipCtaNagbar} from './nagbars/GuildMembershipCtaNagbar';
|
||||
import {MobileDownloadNagbar} from './nagbars/MobileDownloadNagbar';
|
||||
import {PendingBulkDeletionNagbar} from './nagbars/PendingBulkDeletionNagbar';
|
||||
import {PremiumExpiredNagbar} from './nagbars/PremiumExpiredNagbar';
|
||||
@ -66,6 +67,8 @@ export const NagbarContainer: React.FC<NagbarContainerProps> = observer(({nagbar
|
||||
return <DesktopDownloadNagbar key={nagbar.type} isMobile={mobileLayout.enabled} />;
|
||||
case NagbarType.MOBILE_DOWNLOAD:
|
||||
return <MobileDownloadNagbar key={nagbar.type} isMobile={mobileLayout.enabled} />;
|
||||
case NagbarType.GUILD_MEMBERSHIP_CTA:
|
||||
return <GuildMembershipCtaNagbar key={nagbar.type} isMobile={mobileLayout.enabled} />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -162,6 +162,13 @@ export const useNagbarConditions = (): NagbarConditions => {
|
||||
pendingBulkDeletion && !nagbarState.hasPendingBulkDeletionDismissed(pendingBulkDeletionKey),
|
||||
);
|
||||
|
||||
const canShowGuildMembershipCta = (() => {
|
||||
if (nagbarState.forceHideGuildMembershipCta) return false;
|
||||
if (nagbarState.forceGuildMembershipCta) return true;
|
||||
if (!user) return false;
|
||||
return !nagbarState.guildMembershipCtaDismissed;
|
||||
})();
|
||||
|
||||
return {
|
||||
userIsUnclaimed: nagbarState.forceHideUnclaimedAccount
|
||||
? false
|
||||
@ -185,6 +192,7 @@ export const useNagbarConditions = (): NagbarConditions => {
|
||||
canShowDesktopDownload,
|
||||
canShowMobileDownload,
|
||||
hasPendingBulkMessageDeletion,
|
||||
canShowGuildMembershipCta,
|
||||
};
|
||||
};
|
||||
|
||||
@ -208,23 +216,28 @@ export const useActiveNagbars = (conditions: NagbarConditions): Array<NagbarStat
|
||||
visible: conditions.userIsUnclaimed,
|
||||
},
|
||||
{
|
||||
type: NagbarType.EMAIL_VERIFICATION,
|
||||
type: NagbarType.GUILD_MEMBERSHIP_CTA,
|
||||
priority: 2,
|
||||
visible: conditions.canShowGuildMembershipCta,
|
||||
},
|
||||
{
|
||||
type: NagbarType.EMAIL_VERIFICATION,
|
||||
priority: 3,
|
||||
visible: conditions.userNeedsVerification,
|
||||
},
|
||||
{
|
||||
type: NagbarType.PREMIUM_GRACE_PERIOD,
|
||||
priority: 3,
|
||||
priority: 4,
|
||||
visible: conditions.canShowPremiumGracePeriod,
|
||||
},
|
||||
{
|
||||
type: NagbarType.PREMIUM_EXPIRED,
|
||||
priority: 4,
|
||||
priority: 5,
|
||||
visible: conditions.canShowPremiumExpired,
|
||||
},
|
||||
{
|
||||
type: NagbarType.PREMIUM_ONBOARDING,
|
||||
priority: 5,
|
||||
priority: 6,
|
||||
visible: conditions.canShowPremiumOnboarding,
|
||||
},
|
||||
{
|
||||
|
||||
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {Trans} from '@lingui/react/macro';
|
||||
import {observer} from 'mobx-react-lite';
|
||||
import React from 'react';
|
||||
import * as ModalActionCreators from '~/actions/ModalActionCreators';
|
||||
import {modal} from '~/actions/ModalActionCreators';
|
||||
import {Nagbar} from '~/components/layout/Nagbar';
|
||||
import {NagbarButton} from '~/components/layout/NagbarButton';
|
||||
import {NagbarContent} from '~/components/layout/NagbarContent';
|
||||
import {InviteAcceptModal} from '~/components/modals/InviteAcceptModal';
|
||||
import AuthenticationStore from '~/stores/AuthenticationStore';
|
||||
import GuildMemberStore from '~/stores/GuildMemberStore';
|
||||
import InviteStore from '~/stores/InviteStore';
|
||||
import NagbarStore from '~/stores/NagbarStore';
|
||||
import {isGuildInvite} from '~/types/InviteTypes';
|
||||
|
||||
const FLUXER_HQ_INVITE_CODE = 'fluxer-hq';
|
||||
|
||||
export const GuildMembershipCtaNagbar = observer(({isMobile}: {isMobile: boolean}) => {
|
||||
const currentUserId = AuthenticationStore.currentUserId;
|
||||
const inviteState = InviteStore.invites.get(FLUXER_HQ_INVITE_CODE);
|
||||
const invite = inviteState?.data ?? null;
|
||||
|
||||
const [isSubmitting, setIsSubmitting] = React.useState(false);
|
||||
|
||||
if (!currentUserId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (invite && isGuildInvite(invite)) {
|
||||
const guildId = invite.guild.id;
|
||||
const isMember = Boolean(GuildMemberStore.getMember(guildId, currentUserId));
|
||||
if (isMember) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const handleJoinGuild = async () => {
|
||||
if (isSubmitting) return;
|
||||
|
||||
setIsSubmitting(true);
|
||||
try {
|
||||
const module = await import('~/actions/InviteActionCreators');
|
||||
await module.fetchWithCoalescing(FLUXER_HQ_INVITE_CODE);
|
||||
|
||||
const loadedInvite = InviteStore.invites.get(FLUXER_HQ_INVITE_CODE)?.data ?? null;
|
||||
if (loadedInvite && isGuildInvite(loadedInvite)) {
|
||||
const guildId = loadedInvite.guild.id;
|
||||
const isMember = Boolean(GuildMemberStore.getMember(guildId, currentUserId));
|
||||
if (isMember) {
|
||||
NagbarStore.guildMembershipCtaDismissed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
ModalActionCreators.push(modal(() => <InviteAcceptModal code={FLUXER_HQ_INVITE_CODE} />));
|
||||
}
|
||||
};
|
||||
|
||||
const handleDismiss = () => {
|
||||
NagbarStore.guildMembershipCtaDismissed = true;
|
||||
};
|
||||
|
||||
return (
|
||||
<Nagbar
|
||||
isMobile={isMobile}
|
||||
backgroundColor="var(--brand-primary)"
|
||||
textColor="var(--text-on-brand-primary)"
|
||||
onDismiss={handleDismiss}
|
||||
dismissible={true}
|
||||
>
|
||||
<NagbarContent
|
||||
isMobile={isMobile}
|
||||
message={<Trans>Join Fluxer HQ to chat with the team and stay up to date on the latest!</Trans>}
|
||||
actions={
|
||||
<NagbarButton isMobile={isMobile} onClick={handleJoinGuild} submitting={isSubmitting} disabled={isSubmitting}>
|
||||
<Trans>Join Fluxer HQ</Trans>
|
||||
</NagbarButton>
|
||||
}
|
||||
/>
|
||||
</Nagbar>
|
||||
);
|
||||
});
|
||||
@ -28,6 +28,7 @@ export const NagbarType = {
|
||||
BULK_DELETE_PENDING: 'bulk-delete-pending',
|
||||
DESKTOP_DOWNLOAD: 'desktop-download',
|
||||
MOBILE_DOWNLOAD: 'mobile-download',
|
||||
GUILD_MEMBERSHIP_CTA: 'guild-membership-cta',
|
||||
} as const;
|
||||
|
||||
export type NagbarType = (typeof NagbarType)[keyof typeof NagbarType];
|
||||
@ -53,6 +54,7 @@ export interface NagbarConditions {
|
||||
canShowDesktopDownload: boolean;
|
||||
canShowMobileDownload: boolean;
|
||||
hasPendingBulkMessageDeletion: boolean;
|
||||
canShowGuildMembershipCta: boolean;
|
||||
}
|
||||
|
||||
export const UPDATE_DISMISS_KEY = 'fluxer_update_dismissed_until';
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -33,6 +33,7 @@ export interface NagbarSettings {
|
||||
mobileDownloadDismissed: boolean;
|
||||
pendingBulkDeletionDismissed: Record<string, boolean>;
|
||||
invitesDisabledDismissed: Record<string, boolean>;
|
||||
guildMembershipCtaDismissed: boolean;
|
||||
claimAccountModalShownThisSession: boolean;
|
||||
forceOffline: boolean;
|
||||
forceEmailVerification: boolean;
|
||||
@ -49,6 +50,7 @@ export interface NagbarSettings {
|
||||
forceUpdateAvailable: boolean;
|
||||
forceDesktopDownload: boolean;
|
||||
forceMobileDownload: boolean;
|
||||
forceGuildMembershipCta: boolean;
|
||||
forceHideOffline: boolean;
|
||||
forceHideEmailVerification: boolean;
|
||||
forceHideIOSInstall: boolean;
|
||||
@ -64,6 +66,7 @@ export interface NagbarSettings {
|
||||
forceHideUpdateAvailable: boolean;
|
||||
forceHideDesktopDownload: boolean;
|
||||
forceHideMobileDownload: boolean;
|
||||
forceHideGuildMembershipCta: boolean;
|
||||
}
|
||||
|
||||
export type NagbarToggleKey = Exclude<
|
||||
@ -84,6 +87,7 @@ export class NagbarStore implements NagbarSettings {
|
||||
mobileDownloadDismissed = false;
|
||||
pendingBulkDeletionDismissed: Record<string, boolean> = {};
|
||||
invitesDisabledDismissed: Record<string, boolean> = {};
|
||||
guildMembershipCtaDismissed = false;
|
||||
claimAccountModalShownThisSession = false;
|
||||
forceOffline = false;
|
||||
forceEmailVerification = false;
|
||||
@ -100,6 +104,7 @@ export class NagbarStore implements NagbarSettings {
|
||||
forceUpdateAvailable = false;
|
||||
forceDesktopDownload = false;
|
||||
forceMobileDownload = false;
|
||||
forceGuildMembershipCta = false;
|
||||
|
||||
forceHideOffline = false;
|
||||
forceHideEmailVerification = false;
|
||||
@ -116,6 +121,7 @@ export class NagbarStore implements NagbarSettings {
|
||||
forceHideUpdateAvailable = false;
|
||||
forceHideDesktopDownload = false;
|
||||
forceHideMobileDownload = false;
|
||||
forceHideGuildMembershipCta = false;
|
||||
|
||||
constructor() {
|
||||
makeAutoObservable(this, {}, {autoBind: true});
|
||||
@ -136,6 +142,7 @@ export class NagbarStore implements NagbarSettings {
|
||||
'mobileDownloadDismissed',
|
||||
'pendingBulkDeletionDismissed',
|
||||
'invitesDisabledDismissed',
|
||||
'guildMembershipCtaDismissed',
|
||||
]);
|
||||
}
|
||||
|
||||
@ -235,6 +242,14 @@ export class NagbarStore implements NagbarSettings {
|
||||
return this.forceHideUpdateAvailable;
|
||||
}
|
||||
|
||||
getForceGuildMembershipCta(): boolean {
|
||||
return this.forceGuildMembershipCta;
|
||||
}
|
||||
|
||||
getForceHideGuildMembershipCta(): boolean {
|
||||
return this.forceHideGuildMembershipCta;
|
||||
}
|
||||
|
||||
hasPendingBulkDeletionDismissed(scheduleKey: string | null): boolean {
|
||||
if (!scheduleKey) {
|
||||
return false;
|
||||
@ -300,6 +315,7 @@ export class NagbarStore implements NagbarSettings {
|
||||
this.mobileDownloadDismissed = false;
|
||||
this.pendingBulkDeletionDismissed = {};
|
||||
this.invitesDisabledDismissed = {};
|
||||
this.guildMembershipCtaDismissed = false;
|
||||
this.claimAccountModalShownThisSession = false;
|
||||
|
||||
this.forceOffline = false;
|
||||
@ -317,6 +333,7 @@ export class NagbarStore implements NagbarSettings {
|
||||
this.forceUpdateAvailable = false;
|
||||
this.forceDesktopDownload = false;
|
||||
this.forceMobileDownload = false;
|
||||
this.forceGuildMembershipCta = false;
|
||||
|
||||
this.forceHideOffline = false;
|
||||
this.forceHideEmailVerification = false;
|
||||
@ -333,6 +350,7 @@ export class NagbarStore implements NagbarSettings {
|
||||
this.forceHideUpdateAvailable = false;
|
||||
this.forceHideDesktopDownload = false;
|
||||
this.forceHideMobileDownload = false;
|
||||
this.forceHideGuildMembershipCta = false;
|
||||
}
|
||||
|
||||
handleGuildUpdate(action: {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user