Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion apps/builder/app/builder/builder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,6 @@ export const Builder = ({
</Main>
<Topbar
project={project}
hasProPlan={userPlanFeatures.hasProPlan}
css={{ gridArea: "header" }}
loading={
<LoadingBackground
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const formatPublishDate = (date: string) => {
};

export const SectionBackups = () => {
const { hasProPlan } = useStore($userPlanFeatures);
const { hasPaidPlan } = useStore($userPlanFeatures);
const { data, load } = trpcClient.project.publishedBuilds.useQuery();
const projectId = $project.get()?.id ?? "";
useEffect(() => {
Expand Down Expand Up @@ -85,7 +85,7 @@ export const SectionBackups = () => {
<DialogTrigger asChild>
<Button
css={{ justifySelf: "start" }}
disabled={!hasProPlan || options.length === 0}
disabled={!hasPaidPlan || options.length === 0}
>
Restore
</Button>
Expand Down Expand Up @@ -120,7 +120,7 @@ export const SectionBackups = () => {
</Flex>
</DialogContent>
</Dialog>
{!hasProPlan && (
{!hasPaidPlan && (
<PanelBanner>
<img
src={cmsUpgradeBanner}
Expand Down
10 changes: 5 additions & 5 deletions apps/builder/app/builder/features/topbar/domain-checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ interface DomainCheckboxProps {
}

export const DomainCheckbox = (props: DomainCheckboxProps) => {
const hasProPlan = useStore($userPlanFeatures).hasProPlan;
const { allowStagingPublish } = useStore($userPlanFeatures);
const project = useStore($project);

if (project === undefined) {
return;
}

const tooltipContentForFreeUsers = hasProPlan ? undefined : (
const tooltipContentForFreeUsers = allowStagingPublish ? undefined : (
<Flex direction="column" gap="2" css={{ maxWidth: theme.spacing[28] }}>
<Text variant="titles">Publish to Staging</Text>
<Text>
Expand All @@ -55,13 +55,13 @@ export const DomainCheckbox = (props: DomainCheckboxProps) => {
</Flex>
);

const defaultChecked = hasProPlan ? props.defaultChecked : true;
const disabled = hasProPlan ? props.disabled : true;
const defaultChecked = allowStagingPublish ? props.defaultChecked : true;
const disabled = allowStagingPublish ? props.disabled : true;

const hideDomainCheckbox =
project.domainsVirtual.filter(
(domain) => domain.status === "ACTIVE" && domain.verified
).length === 0 && hasProPlan;
).length === 0 && allowStagingPublish;

return (
<div style={{ display: hideDomainCheckbox ? "none" : "contents" }}>
Expand Down
4 changes: 2 additions & 2 deletions apps/builder/app/builder/features/topbar/entri.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ const useEntri = ({ domain, dnsRecords, onClose }: EntriProps) => {

export const Entri = ({ domain, dnsRecords, onClose }: EntriProps) => {
entriGlobalStyles();
const { hasProPlan } = useStore($userPlanFeatures);
const { hasPaidPlan } = useStore($userPlanFeatures);
const { error, isOpen, showDialog } = useEntri({
domain,
dnsRecords,
Expand All @@ -113,7 +113,7 @@ export const Entri = ({ domain, dnsRecords, onClose }: EntriProps) => {
color="primary"
type="button"
onClick={() => {
if (hasProPlan) {
if (hasPaidPlan) {
showDialog();
} else {
setRequestUpgrade(true);
Expand Down
4 changes: 2 additions & 2 deletions apps/builder/app/builder/features/topbar/menu/menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const ViewMenuItem = () => {
};

export const Menu = () => {
const { hasProPlan } = useStore($userPlanFeatures);
const { hasPaidPlan } = useStore($userPlanFeatures);
const authPermit = useStore($authPermit);
const authTokenPermission = useStore($authTokenPermissions);
const authToken = useStore($authToken);
Expand Down Expand Up @@ -287,7 +287,7 @@ export const Menu = () => {
</DropdownMenuSubContent>
</DropdownMenuSub>

{hasProPlan === false && (
{hasPaidPlan === false && (
<>
<DropdownMenuSeparator />
<DropdownMenuItem
Expand Down
114 changes: 44 additions & 70 deletions apps/builder/app/builder/features/topbar/publish.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,7 @@ import {
import { AddDomain } from "./add-domain";
import { humanizeString } from "~/shared/string-utils";
import { trpcClient, nativeClient } from "~/shared/trpc/trpc-client";
import {
isPathnamePattern,
parseComponentName,
type Templates,
} from "@webstudio-is/sdk";
import { isPathnamePattern, type Templates } from "@webstudio-is/sdk";
import { DomainCheckbox, domainToPublishName } from "./domain-checkbox";
import { CopyToClipboard } from "~/builder/shared/copy-to-clipboard";
import { $openProjectSettings } from "~/shared/nano-states/project-settings";
Expand Down Expand Up @@ -236,9 +232,9 @@ const ChangeProjectDomain = ({
);
};

const $usedProFeatures = computed(
[$pages, $dataSources, $instances],
(pages, dataSources, instances) => {
const $restrictedFeatures = computed(
[$pages, $dataSources, $instances, $userPlanFeatures],
(pages, dataSources, instances, userPlanFeatures) => {
const features = new Map<
string,
| undefined
Expand All @@ -248,46 +244,38 @@ const $usedProFeatures = computed(
return features;
}
// specified emails for default webhook form
if ((pages?.meta?.contactEmail ?? "").trim()) {
if (
userPlanFeatures.maxContactEmails === 0 &&
(pages?.meta?.contactEmail ?? "").trim()
) {
features.set("Custom contact email", undefined);
}
// pages with dynamic paths
for (const page of [pages.homePage, ...pages.pages]) {
const awareness = {
pageId: page.id,
instanceSelector: [page.rootInstanceId],
};
// allow catch all for 404 pages on free plan
if (isPathnamePattern(page.path) && page.path !== "/*") {
features.set("Dynamic path", { awareness, view: "pageSettings" });
}
if (page.meta.redirect && page.meta.redirect !== `""`) {
features.set("Redirect", { awareness, view: "pageSettings" });
}
}
// has resource variables
for (const dataSource of dataSources.values()) {
if (dataSource.type === "resource") {
const instanceId = dataSource.scopeInstanceId ?? "";
features.set("Resource variable", {
awareness: findAwarenessByInstanceId(pages, instances, instanceId),
});
if (!userPlanFeatures.allowDynamicData) {
// pages with dynamic paths
for (const page of [pages.homePage, ...pages.pages]) {
const awareness = {
pageId: page.id,
instanceSelector: [page.rootInstanceId],
};
// allow catch all for 404 pages on free plan
if (isPathnamePattern(page.path) && page.path !== "/*") {
features.set("Dynamic path", { awareness, view: "pageSettings" });
}
if (page.meta.redirect && page.meta.redirect !== `""`) {
features.set("Redirect", { awareness, view: "pageSettings" });
}
}
}

// Instances with animations.
for (const instance of instances.values()) {
const [namespace] = parseComponentName(instance.component);
if (namespace === "@webstudio-is/sdk-components-animation") {
features.set("Animation component", {
awareness: findAwarenessByInstanceId(pages, instances, instance.id),
});
// has resource variables
for (const dataSource of dataSources.values()) {
if (dataSource.type === "resource") {
const instanceId = dataSource.scopeInstanceId ?? "";
features.set("Resource variable", {
awareness: findAwarenessByInstanceId(pages, instances, instanceId),
});
}
}
}

// temporary ignore features checks
// return features;
return new Map() as typeof features;
return features;
}
);

Expand All @@ -309,10 +297,10 @@ const Publish = ({
const [isPublishing, setIsPublishing] = useOptimistic(false);
const buttonRef = useRef<HTMLButtonElement>(null);
const [hasSelectedDomains, setHasSelectedDomains] = useState(false);
const hasProPlan = useStore($userPlanFeatures).hasProPlan;
const { hasPaidPlan, allowStagingPublish } = useStore($userPlanFeatures);

useEffect(() => {
if (hasProPlan === false) {
if (allowStagingPublish === false) {
setHasSelectedDomains(true);
return;
}
Expand Down Expand Up @@ -344,13 +332,13 @@ const Publish = ({
return () => {
observer.disconnect();
};
}, [hasProPlan]);
}, [allowStagingPublish]);

const handlePublish = async (formData: FormData) => {
setPublishError(undefined);
setIsPublishing(true);

const domains = hasProPlan
const domains = allowStagingPublish
? formData
.getAll(domainToPublishName)
.map((domainEntry) => domainEntry.toString())
Expand Down Expand Up @@ -436,7 +424,7 @@ const Publish = ({
toast.success(
<>
The project has been successfully published.{" "}
{hasProPlan === false && (
{hasPaidPlan === false && (
<div>
On the free plan, you have {timesLeft} out of{" "}
{maxPublishesAllowedPerUser} daily publications remaining. The
Expand Down Expand Up @@ -641,30 +629,17 @@ const PublishStatic = ({

const useCanAddDomain = () => {
const { load, data } = trpcClient.domain.countTotalDomains.useQuery();
const { maxDomainsAllowedPerUser, hasProPlan } = useStore($userPlanFeatures);
const { maxDomainsAllowedPerUser } = useStore($userPlanFeatures);
const project = useStore($project);

const activeDomainsCount = project?.domainsVirtual.filter(
(domain) => domain.status === "ACTIVE" && domain.verified
).length;

useEffect(() => {
load();
}, [load, activeDomainsCount]);

if (hasProPlan) {
return { canAddDomain: true, maxDomainsAllowedPerUser };
}

if (data?.success === false) {
return { canAddDomain: false, maxDomainsAllowedPerUser };
}

const withinFreeLimit = data
const canAddDomain = data
? data.success && data.data < maxDomainsAllowedPerUser
: true;
const canAddDomain = hasProPlan || withinFreeLimit;

return { canAddDomain, maxDomainsAllowedPerUser };
};

Expand Down Expand Up @@ -704,7 +679,7 @@ const buttonLinkClass = css({
}).toString();

const UpgradeBanner = () => {
const usedProFeatures = useStore($usedProFeatures);
const restrictedFeatures = useStore($restrictedFeatures);
const { canAddDomain } = useCanAddDomain();
const { userPublishCount, maxPublishesAllowedPerUser } =
useUserPublishCount();
Expand All @@ -729,7 +704,7 @@ const UpgradeBanner = () => {
);
}

if (usedProFeatures.size > 0) {
if (restrictedFeatures.size > 0) {
return (
<PanelBanner>
<img
Expand All @@ -740,7 +715,7 @@ const UpgradeBanner = () => {
/>
<Text variant="regularBold">Following Pro features are used:</Text>
<Text as="ul" color="destructive" css={{ paddingLeft: "1em" }}>
{Array.from(usedProFeatures).map(
{Array.from(restrictedFeatures).map(
([message, { awareness, view, info } = {}], index) => (
<li key={index}>
<Flex align="center" gap="1">
Expand Down Expand Up @@ -813,8 +788,7 @@ const Content = (props: {
projectId: Project["id"];
onExportClick: () => void;
}) => {
const usedProFeatures = useStore($usedProFeatures);
const { hasProPlan } = useStore($userPlanFeatures);
const restrictedFeatures = useStore($restrictedFeatures);
const [newDomains, setNewDomains] = useState(new Set<string>());

const project = useStore($project);
Expand Down Expand Up @@ -859,13 +833,13 @@ const Content = (props: {
}}
onExportClick={props.onExportClick}
/>
{hasProPlan === false && <UpgradeBanner />}
<UpgradeBanner />
<Publish
project={project}
refresh={refreshProject}
timesLeft={maxPublishesAllowedPerUser - userPublishCount}
disabled={
(usedProFeatures.size > 0 && hasProPlan === false) ||
restrictedFeatures.size > 0 ||
userPublishCount >= maxPublishesAllowedPerUser
}
/>
Expand Down
10 changes: 2 additions & 8 deletions apps/builder/app/builder/features/topbar/share.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,7 @@ import { ShareProjectContainer } from "~/shared/share-project";
import { $authPermit } from "~/shared/nano-states";
import { $isShareDialogOpen } from "~/builder/shared/nano-states";

export const ShareButton = ({
projectId,
hasProPlan,
}: {
projectId: string;
hasProPlan: boolean;
}) => {
export const ShareButton = ({ projectId }: { projectId: string }) => {
const isShareDialogOpen = useStore($isShareDialogOpen);
const authPermit = useStore($authPermit);

Expand Down Expand Up @@ -50,7 +44,7 @@ export const ShareButton = ({
sideOffset={Number.parseFloat(rawTheme.spacing[8])}
css={{ marginRight: theme.spacing[3] }}
>
<ShareProjectContainer projectId={projectId} hasProPlan={hasProPlan} />
<ShareProjectContainer projectId={projectId} />
<PopoverTitle>Share</PopoverTitle>
</PopoverContent>
</Popover>
Expand Down
5 changes: 2 additions & 3 deletions apps/builder/app/builder/features/topbar/topbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,11 @@ const hideOnMobile: CSS = {

type TopbarProps = {
project: Project;
hasProPlan: boolean;
loading: ReactNode;
css: CSS;
};

export const Topbar = ({ project, hasProPlan, css, loading }: TopbarProps) => {
export const Topbar = ({ project, css, loading }: TopbarProps) => {
const pages = useStore($pages);
return (
<nav className={topbarContainerStyle({ css })}>
Expand Down Expand Up @@ -125,7 +124,7 @@ export const Topbar = ({ project, hasProPlan, css, loading }: TopbarProps) => {
<SyncStatus />

<BuilderModeDropDown />
<ShareButton projectId={project.id} hasProPlan={hasProPlan} />
<ShareButton projectId={project.id} />
<PublishButton projectId={project.id} />
<CloneButton />
</ToolbarToggleGroup>
Expand Down
4 changes: 2 additions & 2 deletions apps/builder/app/builder/shared/image-manager/image-info.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ const ImageInfoContent = ({
asset: Asset;
usages: AssetUsage[];
}) => {
const { hasProPlan } = useStore($userPlanFeatures);
const { hasPaidPlan } = useStore($userPlanFeatures);
const { size, meta, id, name } = asset;
const { basename, ext } = parseAssetName(name);
const [filenameError, setFilenameError] = useState<string>();
Expand Down Expand Up @@ -311,7 +311,7 @@ const ImageInfoContent = ({
if (authPermit === "view") {
downloadError =
"Unavailable in View mode. Switch to Edit to download assets.";
} else if (!hasProPlan) {
} else if (!hasPaidPlan) {
downloadError = "Upgrade to Pro to download assets.";
}

Expand Down
Loading