Skip to content

Commit

Permalink
Fix hydration errors, usage of window and add toggle for cookie based…
Browse files Browse the repository at this point in the history
… preview features (#10602)

* Fix hydration errors, usage of window and add toggle for cookie based preview features

* fix flaky test
  • Loading branch information
hdiniz authored Aug 20, 2024
1 parent a6e16f7 commit 0ba7d99
Show file tree
Hide file tree
Showing 11 changed files with 84 additions and 26 deletions.
1 change: 1 addition & 0 deletions components/DateTime.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const DateTime = ({ value, dateStyle, timeStyle, omitTimeIfMidnight, ...props }:
title={title}
dateTime={date.toISOString()}
onMouseEnter={() => setTitle(generateDateTitle(intl, date))}
suppressHydrationWarning
>
<FormattedDate dateStyle={dateStyle || 'long'} timeStyle={timeStyle} value={date} />
</time>
Expand Down
2 changes: 1 addition & 1 deletion components/InputTypeLocation.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ class InputTypeLocation extends React.Component {
}

isAutocompleteServiceAvailable() {
return window && Boolean(get(window, 'google.maps.places.AutocompleteService'));
return typeof window !== 'undefined' && Boolean(get(window, 'google.maps.places.AutocompleteService'));
}

render() {
Expand Down
36 changes: 22 additions & 14 deletions components/PreviewFeaturesModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,27 @@ const PreviewFeatureCard = ({
context: API_V2_CONTEXT,
});

const togglePreviewFeature = async (featureKey, checked) => {
setIsChecked(checked);
setLoading(true);
await submitEditSettings({
variables: {
account: { slug: LoggedInUser.collective.slug },
key: `earlyAccess.${featureKey}`,
value: checked,
},
});
await refetchLoggedInUser();
setLoading(false);
};
const togglePreviewFeature = React.useCallback(
async checked => {
setIsChecked(checked);
setLoading(true);
if ('setIsEnabled' in feature && typeof feature.setIsEnabled === 'function') {
feature.setIsEnabled(checked);
} else {
await submitEditSettings({
variables: {
account: { slug: LoggedInUser.collective.slug },
key: `earlyAccess.${feature.key}`,
value: checked,
},
});
await refetchLoggedInUser();
}

setLoading(false);
},
[feature, LoggedInUser.collective.slug, submitEditSettings, refetchLoggedInUser],
);

return (
<div className="flex flex-col gap-2 rounded-lg border p-4" key={feature.title}>
Expand All @@ -71,7 +79,7 @@ const PreviewFeatureCard = ({
id={feature.key}
checked={isChecked}
disabled={loading || disabled}
onCheckedChange={checked => togglePreviewFeature(feature.key, checked)}
onCheckedChange={checked => togglePreviewFeature(checked)}
/>
</div>
{dependentFeatures?.length > 0 && (
Expand Down
16 changes: 11 additions & 5 deletions components/contribute-cards/ContributeEvent.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,13 @@ const ContributeEvent = ({ collective, event, ...props }) => {
<Calendar size="1.3em" color="#4E5052" />
<Span ml={2} color="black.700">
{startsAt && (
<time dateTime={startsAt}>
<time suppressHydrationWarning dateTime={startsAt}>
<FormattedDate value={startsAt} month="short" day="numeric" year={showYearOnStartDate} />
</time>
)}
{takesMultipleDays && ' → '}
{(takesMultipleDays || (!startsAt && endsAt)) && (
<time dateTime={endsAt}>
<time suppressHydrationWarning dateTime={endsAt}>
<FormattedDate value={endsAt} month="short" day="numeric" year="numeric" />
</time>
)}
Expand All @@ -64,16 +64,22 @@ const ContributeEvent = ({ collective, event, ...props }) => {
<Span ml={2} color="black.700">
{!takesMultipleDays ? (
<React.Fragment>
<FormattedDate value={startsAt} hour="2-digit" minute="2-digit" />
<span suppressHydrationWarning>
<FormattedDate value={startsAt} hour="2-digit" minute="2-digit" />
</span>
{endsAt && (
<React.Fragment>
{`-`}
<FormattedDate value={endsAt} hour="2-digit" minute="2-digit" timeZoneName="short" />
<span suppressHydrationWarning>
<FormattedDate value={endsAt} hour="2-digit" minute="2-digit" timeZoneName="short" />
</span>
</React.Fragment>
)}
</React.Fragment>
) : (
<FormattedDate value={startsAt} hour="2-digit" minute="2-digit" timeZoneName="short" />
<span suppressHydrationWarning>
<FormattedDate value={startsAt} hour="2-digit" minute="2-digit" timeZoneName="short" />
</span>
)}
</Span>
</Container>
Expand Down
1 change: 1 addition & 0 deletions components/dashboard/sections/AccountSettings.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const AccountSettings = ({ account, section }) => {
const { data, loading } = useQuery(editCollectivePageQuery, {
variables: { slug: account.slug },
fetchPolicy: 'network-only',
ssr: false,
skip: !LoggedInUser,
});
const collective = data?.Collective;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ const HostedCollectives = ({ accountSlug: hostSlug, subpath }: DashboardSectionP
);
const { data: metadata, refetch: refetchMetadata } = useQuery(hostedCollectivesMetadataQuery, {
variables: { hostSlug },
fetchPolicy: 'cache-and-network',
fetchPolicy: typeof window !== 'undefined' ? 'cache-and-network' : 'cache-first',
context: API_V2_CONTEXT,
});

Expand Down Expand Up @@ -175,7 +175,7 @@ const HostedCollectives = ({ accountSlug: hostSlug, subpath }: DashboardSectionP
const { data, error, loading, refetch } = useQuery(hostedCollectivesQuery, {
variables: { hostSlug, ...queryFilter.variables },
context: API_V2_CONTEXT,
fetchPolicy: 'cache-and-network',
fetchPolicy: typeof window !== 'undefined' ? 'cache-and-network' : 'cache-first',
});

useEffect(() => {
Expand Down
2 changes: 1 addition & 1 deletion components/dashboard/sections/collectives/common.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ export const cols: Record<string, ColumnDef<any, any>> = {
return isNil(since) ? (
''
) : (
<div className="whitespace-nowrap">
<div suppressHydrationWarning className="whitespace-nowrap">
<FormattedDate value={since} day="numeric" month="long" year="numeric" />
</div>
);
Expand Down
4 changes: 2 additions & 2 deletions components/dashboard/sections/contributions/Contributions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import useQueryFilter from '../../../../lib/hooks/useQueryFilter';
import i18nOrderStatus from '../../../../lib/i18n/order-status';
import { i18nPaymentMethodProviderType } from '../../../../lib/i18n/payment-method-provider-type';
import type LoggedInUser from '../../../../lib/LoggedInUser';
import { sortSelectOptions } from '../../../../lib/utils';
import { getWebsiteUrl, sortSelectOptions } from '../../../../lib/utils';

import { AccountHoverCard } from '../../../AccountHoverCard';
import Avatar from '../../../Avatar';
Expand Down Expand Up @@ -1046,7 +1046,7 @@ const getContributionActions: (opts: GetContributionActionsOptions) => GetAction

const toAccount = order.toAccount;
const legacyId = order.legacyId;
const orderUrl = new URL(`${toAccount.slug}/orders/${legacyId}`, window.location.origin);
const orderUrl = new URL(`${toAccount.slug}/orders/${legacyId}`, getWebsiteUrl());

actions.secondary.push({
key: 'copy-link',
Expand Down
4 changes: 4 additions & 0 deletions lib/LoggedInUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,10 @@ class LoggedInUser {
return false;
}

if ('isEnabled' in feature && typeof feature.isEnabled === 'function') {
return feature.isEnabled();
}

const enabledByDefault = feature.enabledByDefaultFor?.some(
slug => slug === '*' || this.hasRole([MemberRole.ADMIN, MemberRole.MEMBER], { slug }),
);
Expand Down
38 changes: 38 additions & 0 deletions lib/preview-features.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export enum PREVIEW_FEATURE_KEYS {
HOST_REPORTS = 'HOST_REPORTS',
CROWDFUNDING_REDESIGN = 'CROWDFUNDING_REDESIGN',
TRANSACTIONS_IMPORTS = 'TRANSACTIONS_IMPORTS',
AUTHENTICATED_SSR = 'AUTHENTICATED_SSR',
VERCEL_BACKEND = 'VERCEL_BACKEND',
}

export type PreviewFeature = {
Expand All @@ -20,6 +22,8 @@ export type PreviewFeature = {
env?: Array<'development' | 'test' | 'e2e' | 'staging' | 'production'>; // If set, the feature will be available only in the specified environments.
alwaysEnableInDev?: boolean; // If true, the feature will be enabled by default in development.
dependsOn?: PREVIEW_FEATURE_KEYS;
setIsEnabled?: (enable: boolean) => void;
isEnabled?: () => boolean;
};

/**
Expand Down Expand Up @@ -71,4 +75,38 @@ export const previewFeatures: PreviewFeature[] = [
description: 'A new tool to import batches of transactions.',
publicBeta: true,
},
{
key: PREVIEW_FEATURE_KEYS.AUTHENTICATED_SSR,
title: 'Authenticated SSR',
description: 'Uses cookie based authentication to generate initial page loads on the server',
closedBetaAccessFor: ['opencollective', 'design', 'engineering'],
publicBeta: false,
isEnabled() {
return document.cookie.indexOf('enableAuthSsr') !== -1;
},
setIsEnabled(enabled) {
if (!enabled) {
document.cookie = 'enableAuthSsr=; Max-Age=0';
} else {
document.cookie = 'enableAuthSsr=; Max-Age=9999999';
}
},
},
{
key: PREVIEW_FEATURE_KEYS.VERCEL_BACKEND,
title: 'Vercel Backend',
description: 'Uses Vercel as the frontend backend provider',
closedBetaAccessFor: ['opencollective', 'design', 'engineering'],
publicBeta: false,
isEnabled() {
return document.cookie.indexOf('backend=vercel') !== -1;
},
setIsEnabled(enabled) {
if (!enabled) {
document.cookie = 'backend=; Max-Age=0';
} else {
document.cookie = 'backend=vercel; Max-Age=9999999';
}
},
},
];
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ describe('Contribution Flow: Order', () => {
cy.createCollective({ type: 'ORGANIZATION', name: randomSlug() }).then(collective => {
collectiveSlug = collective.slug;

cy.clock(Date.parse('2042/05/03'));
cy.clock(Date.parse('2042/05/03'), ['Date']);

// Add a paymentMethod to the organization profile
cy.addCreditCardToCollective({ collectiveSlug });
Expand Down

0 comments on commit 0ba7d99

Please sign in to comment.