Skip to content

[pull] master from codesandbox:master #949

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 8, 2022
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ import { useState } from 'react';
import { useEffects } from 'app/overmind';
import { dashboard } from '@codesandbox/common/lib/utils/url-generator';

export type WorkspaceType = 'pro' | 'teamPro';
export type Interval = 'month' | 'year';

export const useCreateCustomerPortal = (
activeTeam: string
): [boolean, () => void] => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import React from 'react';
import { Stack, Text, Link, Button } from '@codesandbox/components';
import { useAppState } from 'app/overmind';
import { format } from 'date-fns';

import css from '@styled-system/css';
import { useCreateCustomerPortal } from 'app/pages/Pro/upgrade/utils';
import { Stack, Text, Link, Button } from '@codesandbox/components';
import { useAppState } from 'app/overmind';
import { useCreateCustomerPortal } from 'app/hooks/useCreateCustomerPortal';

export const Stripe = () => {
const { activeTeam, activeTeamInfo: team } = useAppState();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useAppState } from 'app/overmind';
import { format } from 'date-fns';

import css from '@styled-system/css';
import { useCreateCustomerPortal } from '../../../../../../Pro/upgrade/utils';
import { useCreateCustomerPortal } from 'app/hooks/useCreateCustomerPortal';

export const Stripe = () => {
const { activeTeam, activeTeamInfo: team } = useAppState();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { Stack, Text, Button } from '@codesandbox/components';
import { useCreateCustomerPortal } from 'app/pages/Pro/upgrade/utils';
import { useCreateCustomerPortal } from 'app/hooks/useCreateCustomerPortal';

export const TrialExpiring: React.FC<{
activeTeam: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,38 @@ import {
ThemeProvider,
Stack,
Element,
Link as StyledLink,
Tooltip,
Icon,
Text,
} from '@codesandbox/components';
import { Helmet } from 'react-helmet';
import { Navigation } from 'app/pages/common/Navigation';
import { useCreateCustomerPortal } from 'app/hooks/useCreateCustomerPortal';
import css from '@styled-system/css';
import { sortBy } from 'lodash-es';
import { AnimatePresence, motion } from 'framer-motion';
import { dashboard as dashboardUrls } from '@codesandbox/common/lib/utils/url-generator';
import { useLocation, useHistory } from 'react-router-dom';
import { useLocation, useHistory, Link as RouterLink } from 'react-router-dom';
import { formatCurrency } from 'app/utils/currency';
import { useCreateCheckout } from 'app/hooks';
import { useCreateCustomerPortal, Interval } from './upgrade/utils';
import {
UpgradeButton,
Caption,
Summary,
BoxPlaceholder,
SwitchPlan,
PlanTitle,
} from './upgrade/elements';
import { Switcher } from './upgrade/Switcher';
} from './components/elements';
import { Switcher } from './components/Switcher';
import {
SubscriptionPaymentProvider,
SubscriptionType,
TeamMemberAuthorization,
} from '../../graphql/types';

type Interval = 'month' | 'year';

export const ProUpgrade = () => {
const {
pro: { pageMounted },
Expand Down Expand Up @@ -329,32 +333,46 @@ export const ProUpgrade = () => {
exit={{ opacity: 0, height: 0 }}
style={{ overflow: 'hidden' }}
>
<Caption css={{ paddingTop: 24 }}>
<Element
css={{ display: 'flex', alignItems: 'center' }}
>
Paid seats
<Tooltip label="The amount of paid seats is automatically calculated by the amount of admin and editors per team.">
<Element
css={{ display: 'block', marginLeft: '.5em' }}
>
<svg
width="12"
height="12"
viewBox="0 0 12 12"
fill="none"
xmlns="http://www.w3.org/2000/svg"
style={{ display: 'block' }}
<Stack justify="space-between">
<Caption css={{ paddingTop: 24 }}>
<Element
css={{ display: 'flex', alignItems: 'center' }}
>
Paid seats
<Tooltip label="The amount of paid seats is automatically calculated by the amount of admin and editors per team.">
<Element
css={{ display: 'block', marginLeft: '.5em' }}
>
<path
d="M6 10.625C3.44568 10.625 1.375 8.55432 1.375 6C1.375 3.44568 3.44568 1.375 6 1.375C8.55432 1.375 10.625 3.44568 10.625 6C10.625 8.55432 8.55432 10.625 6 10.625ZM0.625 6C0.625 8.96853 3.03147 11.375 6 11.375C8.96853 11.375 11.375 8.96853 11.375 6C11.375 3.03147 8.96853 0.625002 6 0.625002C3.03147 0.625002 0.625 3.03147 0.625 6ZM6 8.875C6.20711 8.875 6.375 8.70711 6.375 8.5V6C6.375 5.79289 6.20711 5.625 6 5.625C5.79289 5.625 5.625 5.79289 5.625 6V8.5C5.625 8.70711 5.79289 8.875 6 8.875ZM6 4.5C6.2071 4.5 6.375 4.33211 6.375 4.125L6.375 4.0625C6.375 3.8554 6.20711 3.6875 6 3.6875C5.7929 3.6875 5.625 3.85539 5.625 4.0625L5.625 4.125C5.625 4.3321 5.79289 4.5 6 4.5Z"
fill="#C5C5C5"
/>
</svg>
</Element>
</Tooltip>
</Element>
</Caption>
<svg
width="12"
height="12"
viewBox="0 0 12 12"
fill="none"
xmlns="http://www.w3.org/2000/svg"
style={{ display: 'block' }}
>
<path
d="M6 10.625C3.44568 10.625 1.375 8.55432 1.375 6C1.375 3.44568 3.44568 1.375 6 1.375C8.55432 1.375 10.625 3.44568 10.625 6C10.625 8.55432 8.55432 10.625 6 10.625ZM0.625 6C0.625 8.96853 3.03147 11.375 6 11.375C8.96853 11.375 11.375 8.96853 11.375 6C11.375 3.03147 8.96853 0.625002 6 0.625002C3.03147 0.625002 0.625 3.03147 0.625 6ZM6 8.875C6.20711 8.875 6.375 8.70711 6.375 8.5V6C6.375 5.79289 6.20711 5.625 6 5.625C5.79289 5.625 5.625 5.79289 5.625 6V8.5C5.625 8.70711 5.79289 8.875 6 8.875ZM6 4.5C6.2071 4.5 6.375 4.33211 6.375 4.125L6.375 4.0625C6.375 3.8554 6.20711 3.6875 6 3.6875C5.7929 3.6875 5.625 3.85539 5.625 4.0625L5.625 4.125C5.625 4.3321 5.79289 4.5 6 4.5Z"
fill="#C5C5C5"
/>
</svg>
</Element>
</Tooltip>
</Element>
</Caption>

<Caption css={{ paddingTop: 24 }}>
<StyledLink
as={RouterLink}
to={dashboardUrls.settings(activeTeam)}
>
<Stack gap={2}>
<span>Go to team settings</span>
<Icon name="external" size={16} />
</Stack>
</StyledLink>
</Caption>
</Stack>

<BoxPlaceholder>
<span>{amountPaidMember}</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React from 'react';
import { TeamAvatar } from 'app/components/TeamAvatar';
import styled from 'styled-components';
import {
Badge,
Stack,
Avatar,
Menu,
Expand Down Expand Up @@ -41,6 +42,10 @@ export const Switcher: React.FC<{
const members = activeTeamInfo.users.length;
const memberLabel = `${members} member${members > 1 ? 's' : ''}`;
const isPersonalWorkspace = workspaceType === 'pro';
const isFreeWorkspace = ![
SubscriptionType.TeamPro,
SubscriptionType.PersonalPro,
].includes(activeTeamInfo.subscription?.type);

return (
<Stack
Expand All @@ -56,12 +61,16 @@ export const Switcher: React.FC<{
name={activeTeamInfo.name}
/>

<Stack css={{ marginLeft: 24}} direction="vertical">
<WorkspaceName>
<span>{activeTeamInfo.name}</span>
</WorkspaceName>
<Stack css={{ marginLeft: 24 }} direction="vertical">
<Stack align="center" gap={1}>
<WorkspaceName>
<span>{activeTeamInfo.name}</span>
</WorkspaceName>
{isFreeWorkspace && <Badge color="accent">Free</Badge>}
<Icon css={{ color: '#fff' }} name="chevronDown" size={8} />
</Stack>
<WorkspaceType>
{isPersonalWorkspace ? 'personal team' : memberLabel}
{isPersonalWorkspace ? 'Personal' : memberLabel}
</WorkspaceType>
</Stack>
</Stack>
Expand Down Expand Up @@ -102,7 +111,7 @@ export const Switcher: React.FC<{
onSelect={() => setActiveTeam(workspace)}
key={workspace.id}
disabled={disabled}
style={{ opacity: disabled ? 0.5 : 1 }}
style={{ opacity: disabled ? 0.5 : 1, padding: 0 }}
>
<Stack css={{ padding: '12px 24px' }} align="center">
<TeamAvatar
Expand All @@ -115,21 +124,22 @@ export const Switcher: React.FC<{
direction="vertical"
css={{ flex: 1, marginLeft: 19 }}
>
<Stack>
<Text size={4}>{workspace.name}</Text>
{isPro && <ProBadge>Pro</ProBadge>}
<Stack gap={1}>
<Text size={4}>
{workspace.id === personalWorkspaceId
? 'Personal'
: workspace.name}
</Text>
</Stack>

<Text size={3}>
{workspace.id === personalWorkspaceId
? 'personal team'
: seatsLabel}
{workspace.id !== personalWorkspaceId
? seatsLabel
: null}
</Text>
</Stack>

{workspace.id === activeTeamInfo.id && (
<Icon css={{ marginLeft: 16 }} name="simpleCheck" />
)}
{!isPro && <Badge color="accent">Free</Badge>}
</Stack>
</MenuItem>
);
Expand Down Expand Up @@ -247,17 +257,17 @@ const Dialog = styled.div`
`;

const WorkspaceName = styled.p`
font-family: 'TWKEverett', sans-serif;
font-family: 'Inter', sans-serif;
font-style: normal;
font-size: 28px;
font-weight: 500;
line-height: 36px;
letter-spacing: -0.01em;

margin: 0;
position: relative;
text-align: left;
color: #e5e5e5;

font-size: 24px;

& span::-moz-selection {
-webkit-text-stroke: 1px #e5e5e5;
color: transparent;
Expand All @@ -269,15 +279,6 @@ const WorkspaceName = styled.p`
color: transparent;
background: transparent;
}

&:after {
content: '';
position: absolute;
right: -20px;
top: calc(50% - 4px);
border: 5px solid transparent;
border-top: 7px solid white;
}
`;

const WorkspaceType = styled.p`
Expand Down Expand Up @@ -331,18 +332,3 @@ const MenuItem = styled(Menu.Item)`
}
}
`;

const ProBadge = styled.p`
border-radius: 2px;
background-color: rgba(229, 229, 229, 0.1);
color: #c5c5c5;

width: 35px;
height: 18px;

text-align: center;
line-height: 18px;
font-size: 13px;

margin: 0 0 0 8px;
`;
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
import { Button } from '@codesandbox/components';
import styled, { createGlobalStyle, css } from 'styled-components';

export const GlobalFonts = createGlobalStyle`
@font-face {
font-family: "TWKEverett";
src: url("/static/fonts/TWKEverett-Medium-web.woff") format("woff"),
url("/static/fonts/TWKEverett-Medium-web.ttf") format("ttf");
}
`;
import styled, { css } from 'styled-components';

export const PlanTitle = styled.h1`
font-family: 'TWKEverett', sans-serif;
font-family: 'Everett', sans-serif;
font-weight: 500;
letter-spacing: -0.018em;
transition: all 0.6s ease;
Expand Down Expand Up @@ -130,7 +122,7 @@ export const SwitchPlan = styled.button`
line-height: 42px;
margin-top: 18px;
margin-bottom: 4px;
font-family: 'TWKEverett', sans-serif;
font-family: 'Everett', sans-serif;

span {
color: #434343;
Expand Down
4 changes: 2 additions & 2 deletions packages/app/src/app/pages/Pro/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import {
import { useHistory } from 'react-router-dom';
import { signInPageUrl } from '@codesandbox/common/lib/utils/url-generator';

import { ProLegacy } from './legacy';
import { ProUpgrade } from './upgrade';
import { ProLegacy } from './Legacy';
import { ProUpgrade } from './Upgrade';

export const ProPage: React.FC = () => {
const { pageMounted } = useActions().pro;
Expand Down
8 changes: 4 additions & 4 deletions packages/app/src/app/utils/dateTime.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,26 @@ describe(getDaysUntil, () => {
it('returns 0 if the date is today', () => {
const today = new Date();
today.setMinutes(today.getMinutes() + 30); // 30 minutes ahead
expect(getDaysUntil(today)).toBe(0);
expect(getDaysUntil(today.toISOString())).toBe(0);
});

it('returns null if the target is behind now', () => {
const target = new Date();
target.setMinutes(target.getMinutes() - 30); // 30 minutes behind
expect(getDaysUntil(target)).toBe(null);
expect(getDaysUntil(target.toISOString())).toBe(null);
});

it('returns 1 if the date is tomorrow', () => {
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
tomorrow.setHours(11, 0, 0, 0); // Random hour
expect(getDaysUntil(tomorrow)).toBe(1);
expect(getDaysUntil(tomorrow.toISOString())).toBe(1);
});

it('returns 10 if the date is 10 days from now', () => {
const fiveDaysFromNow = new Date();
fiveDaysFromNow.setDate(fiveDaysFromNow.getDate() + 10);
fiveDaysFromNow.setHours(5, 0, 0, 0); // Random hour
expect(getDaysUntil(fiveDaysFromNow)).toBe(10);
expect(getDaysUntil(fiveDaysFromNow.toISOString())).toBe(10);
});
});
11 changes: 6 additions & 5 deletions packages/app/src/app/utils/dateTime.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
export const getDaysUntil = (target: Date): number | null => {
export const getDaysUntil = (target: string | null): number | null => {
if (!target) {
return null;
}

const now = new Date();
const targetDate = new Date(target);

if (now > target) {
if (now > targetDate) {
return null;
}

const dayInMiliseconds = 1000 * 3600 * 24;

const nowOnlyDay = new Date(now.getFullYear(), now.getMonth(), now.getDate());
const targetOnlyDay = new Date(
target.getFullYear(),
target.getMonth(),
target.getDate()
targetDate.getFullYear(),
targetDate.getMonth(),
targetDate.getDate()
);

return (targetOnlyDay.getTime() - nowOnlyDay.getTime()) / dayInMiliseconds;
Expand Down