Skip to content

Commit

Permalink
feat(console,phrases): add bring your ui feature paywall
Browse files Browse the repository at this point in the history
  • Loading branch information
charIeszhao committed Jul 19, 2024
1 parent 33389ee commit 53ae7df
Show file tree
Hide file tree
Showing 9 changed files with 62 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ import * as styles from './index.module.scss';
type Props = {
readonly value?: CustomUiAssets;
readonly onChange: (value: CustomUiAssets) => void;
// eslint-disable-next-line react/boolean-prop-naming
readonly disabled?: boolean;
};

const allowedMimeTypes: AllowedUploadMimeType[] = ['application/zip'];

function CustomUiAssetsUploader({ value, onChange }: Props) {
function CustomUiAssetsUploader({ value, onChange, disabled }: Props) {
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
const [file, setFile] = useState<File>();
const [error, setError] = useState<string>();
Expand Down Expand Up @@ -48,6 +50,7 @@ function CustomUiAssetsUploader({ value, onChange }: Props) {
if (showUploader) {
return (
<FileUploader<{ customUiAssetId: string }>
disabled={disabled}
allowedMimeTypes={allowedMimeTypes}
maxSize={maxUploadFileSize}
uploadUrl="api/sign-in-exp/default/custom-ui-assets"
Expand Down
2 changes: 1 addition & 1 deletion packages/console/src/components/FeatureTag/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import * as styles from './index.module.scss';

export { default as BetaTag } from './BetaTag';

type Props = {
export type Props = {
/**
* Whether the tag should be visible. It should be `true` if the tenant's subscription
* plan has NO access to the feature (paywall), but it will always be visible for dev
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
font: var(--font-body-2);
color: var(--color-text-secondary);
}

.featureTag {
margin-left: _.unit(2);
}
}

.description {
Expand Down
4 changes: 4 additions & 0 deletions packages/console/src/ds-components/FormField/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { ReactElement, ReactNode } from 'react';
import { useTranslation } from 'react-i18next';

import Tip from '@/assets/icons/tip.svg';
import FeatureTag, { type Props as FeatureTagProps } from '@/components/FeatureTag';

import type DangerousRaw from '../DangerousRaw';
import DynamicT from '../DynamicT';
Expand All @@ -25,6 +26,7 @@ export type Props = {
readonly headlineSpacing?: 'default' | 'large';
readonly headlineClassName?: string;
readonly tip?: ToggleTipProps['content'];
readonly featureTag?: FeatureTagProps;
};

function FormField({
Expand All @@ -37,6 +39,7 @@ function FormField({
className,
headlineSpacing = 'default',
tip,
featureTag,
headlineClassName,
}: Props) {
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
Expand All @@ -63,6 +66,7 @@ function FormField({
</IconButton>
</ToggleTip>
)}
{featureTag && <FeatureTag {...featureTag} className={styles.featureTag} />}
<Spacer />
{isRequired && <div className={styles.required}>{t('general.required')}</div>}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,19 @@
}
}

&:hover {
&.disabled {
cursor: not-allowed;
border-color: var(--color-disabled);
color: var(--color-disabled);

.placeholder {
.icon {
color: var(--color-disabled);
}
}
}

&:not(.disabled):hover {
cursor: pointer;
border-color: var(--color-primary);

Expand All @@ -44,7 +56,7 @@
}
}

&.dragActive {
&:not(.disabled).dragActive {
cursor: copy;
background-color: var(--color-hover-variant);
border-color: var(--color-primary);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import { Ring } from '../../Spinner';
import * as styles from './index.module.scss';

export type Props<T extends Record<string, unknown> = UserAssets> = {
// eslint-disable-next-line react/boolean-prop-naming
readonly disabled?: boolean;
readonly maxSize: number; // In bytes
readonly allowedMimeTypes: AllowedUploadMimeType[];
readonly actionDescription?: string;
Expand All @@ -33,6 +35,7 @@ export type Props<T extends Record<string, unknown> = UserAssets> = {
};

function FileUploader<T extends Record<string, unknown> = UserAssets>({
disabled,
maxSize,
allowedMimeTypes,
actionDescription,
Expand Down Expand Up @@ -119,7 +122,7 @@ function FileUploader<T extends Record<string, unknown> = UserAssets>({

const { getRootProps, getInputProps, isDragActive } = useDropzone({
onDrop,
disabled: isUploading,
disabled: isUploading || disabled,
multiple: false,
accept: Object.fromEntries(allowedMimeTypes.map((mimeType) => [mimeType, []])),
});
Expand All @@ -131,6 +134,7 @@ function FileUploader<T extends Record<string, unknown> = UserAssets>({
styles.uploader,
Boolean(uploadError) && styles.uploaderError,
isDragActive && styles.dragActive,
disabled && styles.disabled,
className
)}
>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
@use '@/scss/underscore' as _;

.customCssCodeEditor {
max-height: calc(100vh - 260px);
min-height: 132px; // min-height to show three lines of code
}

.upsell {
margin-top: _.unit(3);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { ReservedPlanId } from '@logto/schemas';
import { useContext } from 'react';
import { Controller, useFormContext } from 'react-hook-form';
import { Trans, useTranslation } from 'react-i18next';

import CustomUiAssetsUploader from '@/components/CustomUiAssetsUploader';
import InlineUpsell from '@/components/InlineUpsell';
import { isDevFeaturesEnabled } from '@/consts/env';
import { SubscriptionDataContext } from '@/contexts/SubscriptionDataProvider';
import Card from '@/ds-components/Card';
import CodeEditor from '@/ds-components/CodeEditor';
import FormField from '@/ds-components/FormField';
Expand All @@ -18,6 +22,8 @@ function CustomUiForm() {
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
const { getDocumentationUrl } = useDocumentationUrl();
const { control } = useFormContext<SignInExperienceForm>();
const { currentPlan } = useContext(SubscriptionDataContext);
const isBringYourUiEnabled = currentPlan.quota.bringYourUiEnabled;

return (
<Card>
Expand Down Expand Up @@ -79,14 +85,29 @@ function CustomUiForm() {
</Trans>
}
descriptionPosition="top"
featureTag={{
isVisible: !isBringYourUiEnabled,
plan: ReservedPlanId.Pro,
}}
>
<Controller
name="customUiAssets"
control={control}
render={({ field: { onChange, value } }) => (
<CustomUiAssetsUploader value={value} onChange={onChange} />
<CustomUiAssetsUploader
disabled={!isBringYourUiEnabled}
value={value}
onChange={onChange}
/>
)}
/>
{!isBringYourUiEnabled && (
<InlineUpsell
className={brandingStyles.upsell}
for="bring_your_ui"
actionButtonText="upsell.view_plans"
/>
)}
</FormField>
)}
</Card>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ const paywall = {
description:
"Upgrade to a paid plan for custom JWT functionality and premium benefits. Don't hesitate to <a>contact us</a> if you have any questions.",
},
bring_your_ui:
'Upgrade to a paid plan for bring your custom UI functionality and premium benefits.',
};

export default Object.freeze(paywall);

0 comments on commit 53ae7df

Please sign in to comment.