Add placeholder to signinup modal's secondary logo (#12079)

closes https://github.com/twentyhq/core-team-issues/issues/972

checks - 

- [x]  If we have an icon it should be displayed as `secondary`

<img width="1064" alt="Screenshot 2025-05-16 at 00 33 42"
src="https://github.com/user-attachments/assets/20716df3-28be-40c5-b0fc-2133fccdad83"
/>

- [x] If no icon is provided, display a placeholder

<img width="1062" alt="Screenshot 2025-05-16 at 00 33 09"
src="https://github.com/user-attachments/assets/0241dafe-3d31-4f8e-a9e4-321634f6d41c"
/>

- [x] Add story for auth logos
<img width="550" alt="Screenshot 2025-05-16 at 16 16 24"
src="https://github.com/user-attachments/assets/3859547d-32c5-469f-879b-a130a36a23fa"
/>

<img width="548" alt="Screenshot 2025-05-16 at 16 16 30"
src="https://github.com/user-attachments/assets/4937fa6a-459a-4c75-86ae-2080b1c8a5ae"
/>

<img width="487" alt="Screenshot 2025-05-16 at 16 16 16"
src="https://github.com/user-attachments/assets/2c634be1-4a51-4b06-a590-cdd7eff91b76"
/>

<img width="556" alt="Screenshot 2025-05-16 at 16 16 07"
src="https://github.com/user-attachments/assets/e4a518b4-c338-45c1-a329-5c9f85319c52"
/>
This commit is contained in:
nitin
2025-05-16 19:51:24 +05:30
committed by GitHub
parent 4017bd48f7
commit 8334fe9528
6 changed files with 87 additions and 13 deletions

View File

@ -1,6 +1,7 @@
import styled from '@emotion/styled';
import { isNonEmptyString } from '@sniptt/guards';
import { getImageAbsoluteURI } from 'twenty-shared/utils';
import { getImageAbsoluteURI, isDefined } from 'twenty-shared/utils';
import { Avatar } from 'twenty-ui/display';
import { UndecoratedLink } from 'twenty-ui/navigation';
import { REACT_APP_SERVER_BASE_URL } from '~/config';
import { useRedirectToDefaultDomain } from '~/modules/domain-manager/hooks/useRedirectToDefaultDomain';
@ -9,6 +10,7 @@ import { AppPath } from '~/modules/types/AppPath';
type LogoProps = {
primaryLogo?: string | null;
secondaryLogo?: string | null;
placeholder?: string | null;
};
const StyledContainer = styled.div`
@ -47,23 +49,27 @@ const StyledPrimaryLogo = styled.div<{ src: string }>`
width: 100%;
`;
export const Logo = (props: LogoProps) => {
export const Logo = ({
primaryLogo,
secondaryLogo,
placeholder,
}: LogoProps) => {
const { redirectToDefaultDomain } = useRedirectToDefaultDomain();
const defaultPrimaryLogoUrl = `${window.location.origin}/images/icons/android/android-launchericon-192-192.png`;
const primaryLogoUrl = getImageAbsoluteURI({
imageUrl: props.primaryLogo ?? defaultPrimaryLogoUrl,
imageUrl: primaryLogo ?? defaultPrimaryLogoUrl,
baseUrl: REACT_APP_SERVER_BASE_URL,
});
const secondaryLogoUrl = isNonEmptyString(props.secondaryLogo)
const secondaryLogoUrl = isNonEmptyString(secondaryLogo)
? getImageAbsoluteURI({
imageUrl: props.secondaryLogo,
imageUrl: secondaryLogo,
baseUrl: REACT_APP_SERVER_BASE_URL,
})
: null;
const isUsingDefaultLogo = !props.primaryLogo;
const isUsingDefaultLogo = !isDefined(primaryLogo);
return (
<StyledContainer>
@ -72,15 +78,26 @@ export const Logo = (props: LogoProps) => {
to={AppPath.SignInUp}
onClick={redirectToDefaultDomain}
>
<StyledPrimaryLogo src={primaryLogoUrl ?? ''} />
<StyledPrimaryLogo src={primaryLogoUrl} />
</UndecoratedLink>
) : (
<StyledPrimaryLogo src={primaryLogoUrl ?? ''} />
<StyledPrimaryLogo src={primaryLogoUrl} />
)}
{secondaryLogoUrl && (
{isDefined(secondaryLogoUrl) ? (
<StyledSecondaryLogoContainer>
<StyledSecondaryLogo src={secondaryLogoUrl} />
</StyledSecondaryLogoContainer>
) : (
isDefined(placeholder) && (
<StyledSecondaryLogoContainer>
<Avatar
size="lg"
placeholder={placeholder}
type="squared"
placeholderColorSeed={placeholder}
/>
</StyledSecondaryLogoContainer>
)
)}
</StyledContainer>
);

View File

@ -0,0 +1,51 @@
import { Meta, StoryObj } from '@storybook/react';
import {
ComponentDecorator,
RecoilRootDecorator,
RouterDecorator,
} from 'twenty-ui/testing';
import { Logo } from '../Logo';
const logoUrl = 'https://picsum.photos/192/192';
const meta: Meta<typeof Logo> = {
title: 'Modules/Auth/Logo',
component: Logo,
decorators: [ComponentDecorator, RecoilRootDecorator, RouterDecorator],
};
export default meta;
type Story = StoryObj<typeof Logo>;
export const WithSecondaryLogo: Story = {
args: {
primaryLogo: null,
secondaryLogo: logoUrl,
placeholder: 'A',
},
};
export const WithPlaceholder: Story = {
args: {
primaryLogo: null,
secondaryLogo: null,
placeholder: 'B',
},
};
export const WithPrimaryAndSecondaryLogo: Story = {
args: {
primaryLogo: logoUrl,
secondaryLogo: logoUrl,
placeholder: 'C',
},
};
export const WithPrimaryLogoAndPlaceholder: Story = {
args: {
primaryLogo: logoUrl,
secondaryLogo: null,
placeholder: 'D',
},
};

View File

@ -18,7 +18,7 @@ const VerifyEmailEffectErrorState = ({ email = 'user@example.com' }) => {
};
const meta: Meta<typeof VerifyEmailEffectErrorState> = {
title: 'Pages/Auth/VerifyEmailEffect',
title: 'Modules/Auth/VerifyEmailEffect',
component: VerifyEmailEffectErrorState,
decorators: [
(Story) => (

View File

@ -19,7 +19,7 @@ const RenderWithModal = (
};
const meta: Meta<typeof EmailVerificationSent> = {
title: 'Pages/Auth/EmailVerificationSent',
title: 'Modules/Auth/EmailVerificationSent',
component: EmailVerificationSent,
decorators: [ComponentDecorator, SnackBarDecorator],
parameters: {

View File

@ -173,7 +173,10 @@ export const PasswordReset = () => {
<Modal.Content isVerticalCentered isHorizontalCentered>
<StyledMainContainer>
<AnimatedEaseIn>
<Logo secondaryLogo={workspacePublicData?.logo} />
<Logo
secondaryLogo={workspacePublicData?.logo}
placeholder={workspacePublicData?.displayName}
/>
</AnimatedEaseIn>
<Title animate>
<Trans>Reset Password</Trans>

View File

@ -41,7 +41,10 @@ const StandardContent = ({
return (
<Modal.Content isVerticalCentered isHorizontalCentered>
<AnimatedEaseIn>
<Logo secondaryLogo={workspacePublicData?.logo} />
<Logo
secondaryLogo={workspacePublicData?.logo}
placeholder={workspacePublicData?.displayName}
/>
</AnimatedEaseIn>
<Title animate>{title}</Title>
{signInUpForm}