Skip to content
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
18 changes: 18 additions & 0 deletions src/assets/icons/purchasable.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
97 changes: 83 additions & 14 deletions src/common/components/ServiceTiles/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { ServiceTile, SM, Tag } from '@appquality/unguess-design-system';
import { t } from 'i18next';
import { ReactComponent as RerunIcon } from '@zendeskgarden/svg-icons/src/12/arrow-retweet-stroke.svg';
import { ReactComponent as UserGroupIcon } from '@zendeskgarden/svg-icons/src/12/user-group-stroke.svg';
import { appTheme } from 'src/app/theme';
import { ReactComponent as FallbackIcon } from 'src/assets/icons/purchasable.svg';
import { ScrollingGrid } from 'src/common/components/ScrollingGrid';
import { CpReqTemplate } from 'src/features/api';
import { CpReqTemplate, Module } from 'src/features/api';

import { Trans, useTranslation } from 'react-i18next';
import styled from 'styled-components';

const AdditionalInfoTag = styled(Tag)`
Expand All @@ -19,8 +22,9 @@ interface ServiceTilesProps {
}

const ServiceTiles = ({ onClick, promoTemplates }: ServiceTilesProps) => {
const { t } = useTranslation();
if (!promoTemplates?.length) return null;

const fallbackBackground = 'linear-gradient(91deg, #AD1846 0%, #E05B4B 100%)';
return (
<>
<ScrollingGrid
Expand All @@ -29,7 +33,68 @@ const ServiceTiles = ({ onClick, promoTemplates }: ServiceTilesProps) => {
title="promo-templates"
>
{promoTemplates.map((template, i) => {
if (!template.strapi) return null;
const handleClick = () => {
onClick(template.id);
};
const targetModule: { output: string } | undefined = JSON.parse(
template.config
).modules.find((module: Module) => module.type === 'target');
const targetTag =
targetModule?.output && Number(targetModule.output) > 0 ? (
<AdditionalInfoTag
key="target_output"
color={appTheme.palette.grey[700]}
hue="#ffff"
isPill
size="medium"
>
<UserGroupIcon style={{ marginRight: appTheme.space.base }} />
<Trans
i18nKey="__SERVICE_TILES_TARGET_OUTPUT"
values={{ output: targetModule.output }}
/>
</AdditionalInfoTag>
) : null;
if (!template.strapi) {
const fallbackTitle = template.name;
const fallbackPrice = template.price || '';
const fallbackIcon = <FallbackIcon />;

const rerunActivityTag = (
<AdditionalInfoTag
key="rerun_activity"
color={appTheme.palette.grey[700]}
hue="#ffff"
isPill
size="medium"
>
<RerunIcon style={{ marginRight: appTheme.space.base }} />
{t('__SERVICE_TILES_FALLBACK_RERUN_ACTIVITY')}
</AdditionalInfoTag>
);
return (
<ScrollingGrid.Item
key={template.id}
role="listitem"
title={fallbackTitle}
data-qa={`service-tile-${i}`}
>
<ServiceTile
title={fallbackTitle}
description={t('__SERVICE_TILES_FALLBACK_DESCRIPTION')}
background={fallbackBackground}
price={fallbackPrice}
icon={fallbackIcon}
additionalInfo={
<div style={{ display: 'flex', gap: '4px' }}>
{[targetTag, rerunActivityTag]}
</div>
}
onClick={handleClick}
/>
</ScrollingGrid.Item>
);
}
const { title, price, tags, image, background, pre_title } =
template.strapi;
const outputs = tags.map((output) => {
Expand All @@ -48,27 +113,31 @@ const ServiceTiles = ({ onClick, promoTemplates }: ServiceTilesProps) => {
);
});

const handleClick = () => {
onClick(template.id);
};

return (
<ScrollingGrid.Item
key={template.id}
role="listitem"
title={title}
title={title || template.name}
data-qa={`service-tile-${i}`}
>
<ServiceTile
title={title}
title={title || template.name}
description={pre_title}
background={background || appTheme.palette.blue[700]}
price={price?.price || ''}
icon={<img alt={title} src={image} />}
background={background || fallbackBackground}
price={price?.price || template.price || ''}
icon={
image ? (
<img alt={title || template.name} src={image} />
) : (
<FallbackIcon />
)
}
superscript={price?.previous_price}
isSuperscriptStrikethrough={!!price?.is_strikethrough}
additionalInfo={
<div style={{ display: 'flex', gap: '4px' }}>{outputs}</div>
<div style={{ display: 'flex', gap: '4px' }}>
{[targetTag, outputs]}
</div>
}
onClick={handleClick}
/>
Expand Down
3 changes: 3 additions & 0 deletions src/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1324,8 +1324,11 @@
"__SENTIMENT_OVERVIEW_SUBTITLE": "Generated from transcript",
"__SENTIMENT_OVERVIEW_TITLE": "Experience Summary",
"__SENTIMENT_TOAST_COPY_MESSAGE": "Sentiment copied to clipboard",
"__SERVICE_TILES_FALLBACK_DESCRIPTION": "Custom Template",
"__SERVICE_TILES_FALLBACK_RERUN_ACTIVITY": "Repeat Activity",
"__SERVICE_TILES_HEADER": "Explore new ways of testing",
"__SERVICE_TILES_SUBTITLE": "Launch <bold>lean tests</bold> autonomosly, get <bold>expert-verified</bold> results",
"__SERVICE_TILES_TARGET_OUTPUT": "{{output}} users",
"__SIDEBAR_CAMPAIGNS_LABEL": "activities",
"__TEMPLATE_CARD_TAILORED_HEADER": "My tailored activities",
"__TEMPLATE_CARD_UNGUESS_HEADER": "UNGUESS template",
Expand Down
3 changes: 3 additions & 0 deletions src/locales/it/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1360,8 +1360,11 @@
"__SENTIMENT_OVERVIEW_SUBTITLE": "",
"__SENTIMENT_OVERVIEW_TITLE": "",
"__SENTIMENT_TOAST_COPY_MESSAGE": "",
"__SERVICE_TILES_FALLBACK_DESCRIPTION": "",
"__SERVICE_TILES_FALLBACK_RERUN_ACTIVITY": "",
"__SERVICE_TILES_HEADER": "",
"__SERVICE_TILES_SUBTITLE": "",
"__SERVICE_TILES_TARGET_OUTPUT": "",
"__SIDEBAR_CAMPAIGNS_LABEL": "campagne",
"__TEMPLATE_CARD_TAILORED_HEADER": "",
"__TEMPLATE_CARD_UNGUESS_HEADER": "",
Expand Down
26 changes: 20 additions & 6 deletions src/pages/Dashboard/LaunchCampaignCards.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
Span,
XXL,
} from '@appquality/unguess-design-system';
import { useCallback, useMemo } from 'react';
import { Trans, useTranslation } from 'react-i18next';
import { appTheme } from 'src/app/theme';
import PlanCreationInterface from 'src/common/components/PlanCreationInterface';
Expand All @@ -28,21 +29,34 @@ const LaunchCampaignCards = () => {
const { data } = useActiveWorkspaceProjects();
const {
promoTemplates,
workspaceNoStrapiTemplates,
workspaceStrapiTemplates,
setIsDrawerOpen,
setSelectedTemplate,
selectedTemplate,
isDrawerOpen,
} = usePromoContext();

const allTemplates = useMemo(
() => [
...workspaceNoStrapiTemplates,
...workspaceStrapiTemplates,
...promoTemplates,
],
[promoTemplates, workspaceNoStrapiTemplates, workspaceStrapiTemplates]
);

const handleCloseDrawer = () => {
setIsDrawerOpen(false);
};

const handleClick = (tid: number) => {
const selected = promoTemplates.find((template) => template.id === tid);
setSelectedTemplate(selected);
setIsDrawerOpen(true);
};
const handleClick = useCallback(
(tid: number) => {
setSelectedTemplate(allTemplates.find((template) => template.id === tid));
setIsDrawerOpen(true);
},
[allTemplates, setSelectedTemplate, setIsDrawerOpen]
);

if (!data) return null;
if (!canView) return null;
Expand Down Expand Up @@ -71,7 +85,7 @@ const LaunchCampaignCards = () => {
</Paragraph>
</Col>
</Row>
<ServiceTiles onClick={handleClick} promoTemplates={promoTemplates} />
<ServiceTiles onClick={handleClick} promoTemplates={allTemplates} />
{selectedTemplate && (
<PlanCreationInterface
isOpen={isDrawerOpen}
Expand Down
51 changes: 47 additions & 4 deletions src/pages/Dashboard/PromoContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ interface PromoContextProps {
isDrawerOpen: boolean;
setIsDrawerOpen: Dispatch<SetStateAction<boolean>>;
promoTemplates: CpReqTemplate[];
workspaceStrapiTemplates: CpReqTemplate[];
workspaceNoStrapiTemplates: CpReqTemplate[];
selectedTemplate?: CpReqTemplate;
setSelectedTemplate: Dispatch<SetStateAction<CpReqTemplate | undefined>>;
}
Expand All @@ -30,7 +32,7 @@ export const PromoContextProvider = ({ children }: { children: ReactNode }) => {
useState<PromoContextProps['selectedTemplate']>();

const { activeWorkspace } = useActiveWorkspace();
const { data } = useGetWorkspacesByWidTemplatesQuery(
const { data: promoTemplatesData } = useGetWorkspacesByWidTemplatesQuery(
{
wid: activeWorkspace?.id.toString() || '',
filterBy: {
Expand All @@ -43,10 +45,23 @@ export const PromoContextProvider = ({ children }: { children: ReactNode }) => {
skip: !activeWorkspace,
}
);
const { data: workspaceTemplatesData } = useGetWorkspacesByWidTemplatesQuery(
{
wid: activeWorkspace?.id.toString() || '',
filterBy: {
isPromo: 0,
},
orderBy: 'order',
order: 'asc',
},
{
skip: !activeWorkspace,
}
);

const promoTemplates = useMemo(() => {
if (!data) return [];
return data.items.reduce<PromoContextProps['promoTemplates']>(
if (!promoTemplatesData) return [];
return promoTemplatesData.items.reduce<PromoContextProps['promoTemplates']>(
(acc, template) => {
if ('strapi' in template) {
acc.push(template);
Expand All @@ -55,20 +70,48 @@ export const PromoContextProvider = ({ children }: { children: ReactNode }) => {
},
[]
);
}, [data]);
}, [promoTemplatesData]);

const workspaceStrapiTemplates = useMemo(() => {
if (!workspaceTemplatesData) return [];
return workspaceTemplatesData.items.reduce<
PromoContextProps['promoTemplates']
>((acc, template) => {
if ('strapi' in template) {
acc.push(template);
}
return acc;
}, []);
}, [workspaceTemplatesData]);

const workspaceNoStrapiTemplates = useMemo(() => {
if (!workspaceTemplatesData) return [];
return workspaceTemplatesData.items.reduce<
PromoContextProps['promoTemplates']
>((acc, template) => {
if (!('strapi' in template)) {
acc.push(template);
}
return acc;
}, []);
}, [workspaceTemplatesData]);

const PromoContextValue = useMemo(
() => ({
isDrawerOpen,
setIsDrawerOpen,
promoTemplates,
workspaceStrapiTemplates,
workspaceNoStrapiTemplates,
selectedTemplate,
setSelectedTemplate,
}),
[
isDrawerOpen,
setIsDrawerOpen,
promoTemplates,
workspaceStrapiTemplates,
workspaceNoStrapiTemplates,
selectedTemplate,
setSelectedTemplate,
]
Expand Down
26 changes: 20 additions & 6 deletions src/pages/Dashboard/empty-state/projectEmptyState.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
XL,
XXL,
} from '@appquality/unguess-design-system';
import { useCallback, useRef } from 'react';
import { useCallback, useMemo, useRef } from 'react';
import { Trans, useTranslation } from 'react-i18next';
import { appTheme } from 'src/app/theme';
import PlanCreationInterface from 'src/common/components/PlanCreationInterface';
Expand Down Expand Up @@ -43,20 +43,34 @@ export const ProjectEmptyState = () => {
const canView = useCanAccessToActiveWorkspace();
const {
promoTemplates,
workspaceStrapiTemplates,
workspaceNoStrapiTemplates,
setIsDrawerOpen,
selectedTemplate,
isDrawerOpen,
setSelectedTemplate,
} = usePromoContext();

const allTemplates = useMemo(
() => [
...workspaceNoStrapiTemplates,
...workspaceStrapiTemplates,
...promoTemplates,
],
[promoTemplates, workspaceNoStrapiTemplates, workspaceStrapiTemplates]
);

const handleCloseDrawer = useCallback(() => {
setIsDrawerOpen(false);
}, [setIsDrawerOpen]);

const handleClick = (tid: number) => {
setSelectedTemplate(promoTemplates.find((template) => template.id === tid));
setIsDrawerOpen(true);
};
const handleClick = useCallback(
(tid: number) => {
setSelectedTemplate(allTemplates.find((template) => template.id === tid));
setIsDrawerOpen(true);
},
[allTemplates, setSelectedTemplate, setIsDrawerOpen]
);

return (
<EmptyProjectContainer
Expand Down Expand Up @@ -93,7 +107,7 @@ export const ProjectEmptyState = () => {
<div style={{ zIndex: 1, position: 'relative' }}>
<ServiceTiles
onClick={handleClick}
promoTemplates={promoTemplates}
promoTemplates={allTemplates}
/>
</div>
<UGLogoMedium
Expand Down
4 changes: 3 additions & 1 deletion src/pages/JoinPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,9 @@ const LogoWrapper = styled.div`
const JoinPage = () => {
const { t } = useTranslation();
const [searchParams] = useSearchParams();
const { isSuccess: isLogged } = useGetUsersMeQuery();
const { isSuccess: isLogged } = useGetUsersMeQuery(undefined, {
refetchOnFocus: true,
});
const navigate = useNavigate();
const { profile, token } = useParams();
const shouldSkipQuery = isLogged || !(profile && token);
Expand Down
Loading
Loading