@treely/strapi-slices 5.15.0 → 5.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/README.md +6 -0
  2. package/dist/components/CreditsAvailableBadge/CreditsAvailableBadge.d.ts +2 -2
  3. package/dist/models/PortfolioProject.d.ts +0 -2
  4. package/dist/models/fpm/FPMProject.d.ts +7 -0
  5. package/dist/models/strapi/StrapiProject.d.ts +0 -2
  6. package/dist/rootMessages.de.d.ts +0 -4
  7. package/dist/rootMessages.en.d.ts +0 -4
  8. package/dist/slices/ProjectGridCard/ProjectGridCard.d.ts +6 -0
  9. package/dist/slices/ProjectGridCard/index.d.ts +2 -0
  10. package/dist/slices/ProjectsGrid/ProjectsGrid.d.ts +3 -1
  11. package/dist/slices/ProjectsMap/MapMarker.d.ts +3 -3
  12. package/dist/strapi-slices.cjs.development.js +172 -161
  13. package/dist/strapi-slices.cjs.development.js.map +1 -1
  14. package/dist/strapi-slices.cjs.production.min.js +1 -1
  15. package/dist/strapi-slices.cjs.production.min.js.map +1 -1
  16. package/dist/strapi-slices.esm.js +175 -164
  17. package/dist/strapi-slices.esm.js.map +1 -1
  18. package/dist/test/integrationMocks/fpmPortoflioProjectMock.d.ts +3 -0
  19. package/dist/utils/getMessages.d.ts +0 -8
  20. package/package.json +1 -1
  21. package/src/components/CreditsAvailableBadge/CreditsAvailableBadge.test.tsx +8 -6
  22. package/src/components/CreditsAvailableBadge/CreditsAvailableBadge.tsx +34 -22
  23. package/src/components/CreditsAvailableBadge/messages.de.ts +1 -1
  24. package/src/components/portfolio/ProjectInfo/ProjectInfo.tsx +3 -7
  25. package/src/integrations/fpmClient.ts +7 -1
  26. package/src/integrations/strapi/getPortfolioProjects.test.ts +2 -2
  27. package/src/integrations/strapi/getPortfolioProjects.ts +4 -7
  28. package/src/integrations/strapi/getStaticPropsFromStrapi.ts +2 -1
  29. package/src/integrations/strapi/getStrapiCollectionType.ts +2 -1
  30. package/src/integrations/strapi/getStrapiSingleType.ts +3 -1
  31. package/src/integrations/strapi/strapiClient.ts +7 -1
  32. package/src/models/PortfolioProject.ts +0 -2
  33. package/src/models/fpm/FPMProject.ts +8 -0
  34. package/src/models/strapi/StrapiProject.ts +0 -2
  35. package/src/rootMessages.de.ts +0 -2
  36. package/src/rootMessages.en.ts +0 -2
  37. package/src/slices/ProjectFacts/ProjectFacts.stories.tsx +1 -2
  38. package/src/slices/ProjectGridCard/ProjectGridCard.test.tsx +54 -0
  39. package/src/slices/ProjectGridCard/ProjectGridCard.tsx +57 -0
  40. package/src/slices/ProjectGridCard/index.ts +3 -0
  41. package/src/slices/ProjectsGrid/ProjectsGrid.stories.tsx +1 -1
  42. package/src/slices/ProjectsGrid/ProjectsGrid.test.tsx +0 -2
  43. package/src/slices/ProjectsGrid/ProjectsGrid.tsx +5 -3
  44. package/src/slices/ProjectsMap/MapMarker.test.tsx +3 -2
  45. package/src/slices/ProjectsMap/MapMarker.tsx +9 -12
  46. package/src/slices/ProjectsMap/ProjectsMap.stories.tsx +0 -2
  47. package/src/slices/ProjectsMap/ProjectsMap.tsx +1 -1
  48. package/src/slices/TextWithCard/TextWithCard.stories.tsx +2 -3
  49. package/src/slices/TextWithCard/TextWithCard.tsx +2 -2
  50. package/src/test/integrationMocks/fpmPortoflioProjectMock.ts +16 -0
  51. package/src/test/integrationMocks/fpmProjectMock.ts +2 -1
  52. package/src/test/integrationMocks/portfolioProjectMock.ts +1 -3
  53. package/src/test/mocks/portfolioProjectMock.ts +0 -2
  54. package/src/test/strapiMocks/strapiProject.ts +0 -2
  55. package/dist/components/portfolio/PortfolioProjectCard/PortfolioProjectCard.d.ts +0 -6
  56. package/dist/components/portfolio/PortfolioProjectCard/index.d.ts +0 -2
  57. package/dist/components/portfolio/PortfolioProjectCard/messages.de.d.ts +0 -7
  58. package/dist/components/portfolio/PortfolioProjectCard/messages.en.d.ts +0 -7
  59. package/dist/models/CreditsAvailableState.d.ts +0 -7
  60. package/src/components/portfolio/PortfolioProjectCard/PortfolioProjectCard.test.tsx +0 -53
  61. package/src/components/portfolio/PortfolioProjectCard/PortfolioProjectCard.tsx +0 -69
  62. package/src/components/portfolio/PortfolioProjectCard/index.ts +0 -3
  63. package/src/components/portfolio/PortfolioProjectCard/messages.de.ts +0 -8
  64. package/src/components/portfolio/PortfolioProjectCard/messages.en.ts +0 -8
  65. package/src/models/CreditsAvailableState.ts +0 -8
@@ -0,0 +1,3 @@
1
+ import { PortfolioProject } from '../..';
2
+ declare const fpmPortfolioProjectMock: PortfolioProject;
3
+ export default fpmPortfolioProjectMock;
@@ -59,10 +59,6 @@ declare const getMessages: (locale: string) => {
59
59
  'features.projectInfo.properties.forecastedAmountYear.toolTip': string;
60
60
  'features.projectInfo.properties.riskBuffer': string;
61
61
  'features.projectInfo.properties.year': string;
62
- 'components.portfolioProjectCard.text.yes': string;
63
- 'components.portfolioProjectCard.text.some': string;
64
- 'components.portfolioProjectCard.text.no': string;
65
- 'components.portfolioProjectCard.text.notYet': string;
66
62
  'features.portfolio.documentsDownloadList.projectDocuments': string;
67
63
  'features.portfolio.documentsDownloadList.downloadDocument': string;
68
64
  'components.creditsAvailableBadge.text.yes': string;
@@ -130,10 +126,6 @@ declare const getMessages: (locale: string) => {
130
126
  'features.projectInfo.properties.forecastedAmountYear.label': string;
131
127
  'features.projectInfo.properties.riskBuffer': string;
132
128
  'features.projectInfo.properties.year': string;
133
- 'components.portfolioProjectCard.text.yes': string;
134
- 'components.portfolioProjectCard.text.some': string;
135
- 'components.portfolioProjectCard.text.no': string;
136
- 'components.portfolioProjectCard.text.notYet': string;
137
129
  'features.portfolio.documentsDownloadList.projectDocuments': string;
138
130
  'features.portfolio.documentsDownloadList.downloadDocument': string;
139
131
  'components.creditsAvailableBadge.text.yes': string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@treely/strapi-slices",
3
- "version": "5.15.0",
3
+ "version": "5.16.0",
4
4
  "license": "MIT",
5
5
  "author": "Tree.ly FlexCo",
6
6
  "description": "@treely/strapi-slices is a open source library maintained by Tree.ly.",
@@ -1,13 +1,13 @@
1
1
  import React from 'react';
2
2
  import { render, screen } from '../../test/testUtils';
3
- import CreditsAvailableState from '../../models/CreditsAvailableState';
4
3
  import CreditsAvailableBadge, {
5
4
  CreditsAvailableBadgeProps,
6
5
  } from './CreditsAvailableBadge';
7
6
  import messagesEn from './messages.en';
7
+ import { CreditAvailability } from '../../models/fpm/FPMProject';
8
8
 
9
9
  const defaultProps: CreditsAvailableBadgeProps = {
10
- status: CreditsAvailableState.YES,
10
+ status: CreditAvailability.CREDITS_AVAILABLE,
11
11
  };
12
12
 
13
13
  const setup = (props: Partial<CreditsAvailableBadgeProps> = {}) => {
@@ -34,12 +34,14 @@ describe('The CreditsAvailableBadge component', () => {
34
34
  screen.getByText(messagesEn['components.creditsAvailableBadge.text.yes'])
35
35
  ).toBeInTheDocument();
36
36
  expect(
37
- screen.getByText(messagesEn['components.creditsAvailableBadge.text.yes'])
37
+ screen
38
+ .getByText(messagesEn['components.creditsAvailableBadge.text.yes'])
39
+ .closest('a')
38
40
  ).toHaveAttribute('href', 'link-to');
39
41
  });
40
42
 
41
43
  it('renders correctly for the "some" case', () => {
42
- setup({ status: CreditsAvailableState.SOME });
44
+ setup({ status: CreditAvailability.SOME_CREDITS_AVAILABLE });
43
45
 
44
46
  expect(
45
47
  screen.getByText(messagesEn['components.creditsAvailableBadge.text.some'])
@@ -47,7 +49,7 @@ describe('The CreditsAvailableBadge component', () => {
47
49
  });
48
50
 
49
51
  it('renders correctly for the "no" case', () => {
50
- setup({ status: CreditsAvailableState.NO });
52
+ setup({ status: CreditAvailability.NO_CREDITS_AVAILABLE });
51
53
 
52
54
  expect(
53
55
  screen.getByText(messagesEn['components.creditsAvailableBadge.text.no'])
@@ -55,7 +57,7 @@ describe('The CreditsAvailableBadge component', () => {
55
57
  });
56
58
 
57
59
  it('renders correctly for the "notYet" case', () => {
58
- setup({ status: CreditsAvailableState.NOT_YET });
60
+ setup({ status: CreditAvailability.SOON_CREDITS_AVAILABLE });
59
61
 
60
62
  expect(
61
63
  screen.getByText(
@@ -1,11 +1,12 @@
1
1
  import React, { useContext } from 'react';
2
- import CreditsAvailableState from '../../models/CreditsAvailableState';
3
- import { Badge } from 'boemly';
2
+ import { Flex, Spacer, Tag, Text } from 'boemly';
4
3
  import NextLink from 'next/link';
5
4
  import { IntlContext } from '../ContextProvider';
5
+ import { CreditAvailability } from '../../models/fpm/FPMProject';
6
+ import { Info } from '@phosphor-icons/react';
6
7
 
7
8
  export interface CreditsAvailableBadgeProps {
8
- status: CreditsAvailableState;
9
+ status: CreditAvailability;
9
10
  href?: string;
10
11
  }
11
12
 
@@ -16,40 +17,51 @@ const CreditsAvailableBadge = ({
16
17
  const { formatMessage } = useContext(IntlContext);
17
18
 
18
19
  const variants: Record<
19
- CreditsAvailableState,
20
- { color: string; text: string }
20
+ CreditAvailability,
21
+ { message: string; color: string }
21
22
  > = {
22
- [CreditsAvailableState.YES]: {
23
- color: 'green',
24
- text: formatMessage({ id: 'components.creditsAvailableBadge.text.yes' }),
23
+ [CreditAvailability.CREDITS_AVAILABLE]: {
24
+ message: formatMessage({
25
+ id: 'components.creditsAvailableBadge.text.yes',
26
+ }),
27
+ color: 'var(--boemly-colors-primary-800)',
25
28
  },
26
- [CreditsAvailableState.SOME]: {
27
- color: 'orange',
28
- text: formatMessage({ id: 'components.creditsAvailableBadge.text.some' }),
29
+ [CreditAvailability.NO_CREDITS_AVAILABLE]: {
30
+ message: formatMessage({
31
+ id: 'components.creditsAvailableBadge.text.no',
32
+ }),
33
+ color: 'var(--boemly-colors-red-600)',
29
34
  },
30
- [CreditsAvailableState.NO]: {
31
- color: 'red',
32
- text: formatMessage({ id: 'components.creditsAvailableBadge.text.no' }),
35
+ [CreditAvailability.SOME_CREDITS_AVAILABLE]: {
36
+ message: formatMessage({
37
+ id: 'components.creditsAvailableBadge.text.some',
38
+ }),
39
+ color: 'var(--boemly-colors-orange-500)',
33
40
  },
34
- [CreditsAvailableState.NOT_YET]: {
35
- color: 'blue',
36
- text: formatMessage({
41
+ [CreditAvailability.SOON_CREDITS_AVAILABLE]: {
42
+ message: formatMessage({
37
43
  id: 'components.creditsAvailableBadge.text.notYet',
38
44
  }),
45
+ color: 'var(--boemly-colors-blue-500)',
39
46
  },
40
47
  };
41
48
 
42
49
  const variant = variants[status];
43
50
 
44
51
  return (
45
- <Badge
52
+ <Flex
53
+ justifyContent="flex-start"
46
54
  as={href ? NextLink : undefined}
47
55
  href={href}
48
- colorScheme={variant.color}
49
- width="fit-content"
50
56
  >
51
- {variant.text}
52
- </Badge>
57
+ <Tag backgroundColor={variant.color} mt="2" mb="1">
58
+ <Info size={12} color="white" weight="fill" />
59
+ <Spacer width="1" />
60
+ <Text color="white" size="xsLowBold">
61
+ {variant.message}
62
+ </Text>
63
+ </Tag>
64
+ </Flex>
53
65
  );
54
66
  };
55
67
 
@@ -2,6 +2,6 @@ const messagesDe = {
2
2
  'components.creditsAvailableBadge.text.yes': 'Credits verfügbar',
3
3
  'components.creditsAvailableBadge.text.some': 'Einige verbleibende Credits',
4
4
  'components.creditsAvailableBadge.text.no': 'Keine verbleibenden Credits',
5
- 'components.creditsAvailableBadge.text.notYet': 'Gutschriften bald verfügbar',
5
+ 'components.creditsAvailableBadge.text.notYet': 'Credits bald verfügbar',
6
6
  };
7
7
  export default messagesDe;
@@ -248,13 +248,9 @@ export const ProjectInfo: React.FC<ProjectInfoProps> = ({
248
248
  <></>
249
249
  )}
250
250
 
251
- {project.creditsAvailable ? (
252
- <Box mt="2">
253
- <CreditsAvailableBadge status={project.creditsAvailable} />
254
- </Box>
255
- ) : (
256
- <></>
257
- )}
251
+ <Box mt="2">
252
+ <CreditsAvailableBadge status={project.creditAvailability} />
253
+ </Box>
258
254
  </Container>
259
255
  );
260
256
  };
@@ -8,7 +8,13 @@ const fpmClient = setupCache(
8
8
  baseURL: `${FPM_API_URI}/v1`,
9
9
  paramsSerializer: (p) => qs.stringify(p, { encodeValuesOnly: true }),
10
10
  timeout: 5000,
11
- })
11
+ }),
12
+ {
13
+ ttl:
14
+ FPM_API_URI.includes('127.0.0.1') || FPM_API_URI.includes('localhost')
15
+ ? 0
16
+ : 10 * 60 * 1000, // 10 minutes
17
+ }
12
18
  );
13
19
 
14
20
  export default fpmClient;
@@ -27,7 +27,7 @@ describe('The getPortfolioProjects function', () => {
27
27
  expect(projects[0]).toStrictEqual({
28
28
  ...fpmProjectMock,
29
29
  slug: strapiProjectMock.attributes.slug,
30
- creditsAvailable: strapiProjectMock.attributes.creditsAvailable,
30
+ creditAvailability: fpmProjectMock.creditAvailability,
31
31
  });
32
32
  });
33
33
 
@@ -50,7 +50,7 @@ describe('The getPortfolioProjects function', () => {
50
50
  expect(projects[0]).toStrictEqual({
51
51
  ...fpmProjectMock,
52
52
  slug: strapiProjectMock.attributes.slug,
53
- creditsAvailable: strapiProjectMock.attributes.creditsAvailable,
53
+ creditAvailability: fpmProjectMock.creditAvailability,
54
54
  });
55
55
  });
56
56
  });
@@ -15,6 +15,7 @@ const getPortfolioProjects = async (
15
15
  locale: string = 'en',
16
16
  preview: boolean = false
17
17
  ): Promise<PortfolioProject[]> => {
18
+ const cache = preview ? false : undefined;
18
19
  const params: Record<string, any> = {
19
20
  populate: 'deep,6',
20
21
  locale,
@@ -30,17 +31,16 @@ const getPortfolioProjects = async (
30
31
  { data: strapiProjectsLocalized },
31
32
  { data: strapiProjectsEnglish },
32
33
  ] = await Promise.all([
33
- fpmClient.get<FPMProject[]>('/public/projects'),
34
+ fpmClient.get<FPMProject[]>('/public/projects', { cache }),
34
35
  strapiClient.get<IStrapiResponse<IStrapiData<StrapiProject>[]>>(
35
36
  '/projects',
36
- {
37
- params,
38
- }
37
+ { params, cache }
39
38
  ),
40
39
  strapiClient.get<IStrapiResponse<IStrapiData<StrapiProject>[]>>(
41
40
  '/projects',
42
41
  {
43
42
  params: { ...params, locale: FALLBACK_LOCALE },
43
+ cache,
44
44
  }
45
45
  ),
46
46
  ]);
@@ -64,9 +64,6 @@ const getPortfolioProjects = async (
64
64
  if (strapiProject?.attributes.slug) {
65
65
  toReturn.slug = strapiProject.attributes.slug;
66
66
  }
67
- if (strapiProject?.attributes.creditsAvailable) {
68
- toReturn.creditsAvailable = strapiProject?.attributes.creditsAvailable;
69
- }
70
67
  if (strapiProject?.attributes.thumbnail) {
71
68
  toReturn.thumbnail = strapiProject?.attributes.thumbnail;
72
69
  }
@@ -14,6 +14,7 @@ const getStaticPropsFromStrapi = async (
14
14
  path: string,
15
15
  { locale = 'en', slug, preview = false, filters = {} }: Options
16
16
  ): Promise<AxiosResponse> => {
17
+ const cache = preview ? false : undefined;
17
18
  const enrichedFilters: Record<string, string> = filters;
18
19
 
19
20
  if (slug) {
@@ -31,7 +32,7 @@ const getStaticPropsFromStrapi = async (
31
32
  params.publicationState = 'preview';
32
33
  }
33
34
 
34
- return strapiClient.get(path, { params });
35
+ return strapiClient.get(path, { params, cache });
35
36
  };
36
37
 
37
38
  export default getStaticPropsFromStrapi;
@@ -22,6 +22,7 @@ const getStrapiCollectionType = async <
22
22
  key: K,
23
23
  { locale = 'en', preview = false, filters = {} }: Options
24
24
  ): Promise<IStrapiData<T>[]> => {
25
+ const cache = preview ? false : undefined;
25
26
  const params: Record<string, any> = {
26
27
  populate: 'deep,6',
27
28
  locale: 'all',
@@ -35,7 +36,7 @@ const getStrapiCollectionType = async <
35
36
 
36
37
  const { data } = await strapiClient.get<IStrapiResponse<IStrapiData<T>[]>>(
37
38
  path,
38
- { params }
39
+ { params, cache }
39
40
  );
40
41
 
41
42
  const localizedResponses = data.data.filter(
@@ -17,6 +17,7 @@ const getStrapiSingleType = async <T>(
17
17
  path: string,
18
18
  { locale = 'en', preview = false, filters = {} }: Options
19
19
  ): Promise<IStrapiData<T>> => {
20
+ const cache = preview ? false : undefined;
20
21
  const params: Record<string, any> = {
21
22
  populate: 'deep,6',
22
23
  locale,
@@ -31,13 +32,14 @@ const getStrapiSingleType = async <T>(
31
32
  let response: AxiosResponse<IStrapiResponse<IStrapiData<T>>>;
32
33
 
33
34
  try {
34
- response = await strapiClient.get(path, { params });
35
+ response = await strapiClient.get(path, { params, cache });
35
36
  return response.data.data;
36
37
  } catch (error: any) {
37
38
  if (error.isAxiosError && error.response?.status === 404) {
38
39
  // Retry request with fallback locale
39
40
  response = await strapiClient.get(path, {
40
41
  params: { ...params, locale: STRAPI_FALLBACK_LOCALE },
42
+ cache,
41
43
  });
42
44
 
43
45
  return response.data.data;
@@ -8,7 +8,13 @@ const strapiClient = setupCache(
8
8
  baseURL: `${STRAPI_URI}/api`,
9
9
  paramsSerializer: (p) => qs.stringify(p, { encodeValuesOnly: true }),
10
10
  timeout: 60_000,
11
- })
11
+ }),
12
+ {
13
+ ttl:
14
+ STRAPI_URI.includes('127.0.0.1') || STRAPI_URI.includes('localhost')
15
+ ? 0
16
+ : 10 * 60 * 1000, // 10 minutes
17
+ }
12
18
  );
13
19
 
14
20
  export default strapiClient;
@@ -1,5 +1,4 @@
1
1
  import { StrapiImage } from '..';
2
- import CreditsAvailableState from './CreditsAvailableState';
3
2
  import FPMProject from './fpm/FPMProject';
4
3
 
5
4
  interface PortfolioProject extends FPMProject {
@@ -7,7 +6,6 @@ interface PortfolioProject extends FPMProject {
7
6
  slug?: string;
8
7
  portfolioHost?: string;
9
8
  thumbnail?: StrapiImage | null;
10
- creditsAvailable?: CreditsAvailableState;
11
9
  footerSubTitle?: string;
12
10
  }
13
11
 
@@ -1,5 +1,12 @@
1
1
  import Issuer from './Issuer';
2
2
 
3
+ export enum CreditAvailability {
4
+ CREDITS_AVAILABLE = 'credits_available',
5
+ NO_CREDITS_AVAILABLE = 'no_credits_available',
6
+ SOME_CREDITS_AVAILABLE = 'some_credits_available',
7
+ SOON_CREDITS_AVAILABLE = 'soon_credits_available',
8
+ }
9
+
3
10
  interface FPMProject {
4
11
  id: string;
5
12
  title: string;
@@ -33,6 +40,7 @@ interface FPMProject {
33
40
  forecastedAmountYearly?: number;
34
41
  riskBuffer?: number;
35
42
  defaultIssuer?: Issuer;
43
+ creditAvailability: CreditAvailability;
36
44
 
37
45
  createdAt: Date;
38
46
  updatedAt: Date;
@@ -1,4 +1,3 @@
1
- import CreditsAvailableState from '../CreditsAvailableState';
2
1
  import Locale from '../Locale';
3
2
  import IStrapi from './IStrapi';
4
3
  import IStrapiData from './IStrapiData';
@@ -12,7 +11,6 @@ interface StrapiProject {
12
11
  slug: string;
13
12
  locale: Locale;
14
13
  fpmProjectId?: string;
15
- creditsAvailable?: CreditsAvailableState;
16
14
  footerSubTitle?: string;
17
15
  createdAt: string;
18
16
  updatedAt: string;
@@ -8,7 +8,6 @@ import portfolioDocumentsDownloadListMessagesDe from './components/portfolio/Doc
8
8
  import projectFactsMessagesDe from './slices/ProjectFacts/messages.de';
9
9
  import projectsMapMessagesDe from './slices/ProjectsMap/messages.de';
10
10
  import portfolioProjectInfoMessagesDe from './components/portfolio/ProjectInfo/messages.de';
11
- import portfolioProjectCardMessagesDe from './components/portfolio/PortfolioProjectCard/messages.de';
12
11
  import portfolioSmallCheckoutMessagesDe from './components/portfolio/SmallCheckout/messages.de';
13
12
  import shopCheckoutMessagesDe from './slices/ShopCheckout/messages.de';
14
13
  import textCarouselMessagesDe from './slices/TextCarousel/messages.de';
@@ -22,7 +21,6 @@ const rootMessagesDe = {
22
21
  //
23
22
  ...creditsAvailableBadgeMessagesDe,
24
23
  ...portfolioDocumentsDownloadListMessagesDe,
25
- ...portfolioProjectCardMessagesDe,
26
24
  ...portfolioProjectInfoMessagesDe,
27
25
  ...portfolioSmallCheckoutMessagesDe,
28
26
 
@@ -8,7 +8,6 @@ import portfolioDocumentsDownloadListMessagesEn from './components/portfolio/Doc
8
8
  import projectFactsMessagesEn from './slices/ProjectFacts/messages.en';
9
9
  import projectsMapMessagesEn from './slices/ProjectsMap/messages.en';
10
10
  import portfolioProjectInfoMessagesEn from './components/portfolio/ProjectInfo/messages.en';
11
- import portfolioProjectCardMessagesEn from './components/portfolio/PortfolioProjectCard/messages.en';
12
11
  import portfolioSmallCheckoutMessagesEn from './components/portfolio/SmallCheckout/messages.en';
13
12
  import shopCheckoutMessagesEn from './slices/ShopCheckout/messages.en';
14
13
  import textCarouselMessagesEn from './slices/TextCarousel/messages.en';
@@ -22,7 +21,6 @@ const rootMessagesEn = {
22
21
  //
23
22
  ...creditsAvailableBadgeMessagesEn,
24
23
  ...portfolioDocumentsDownloadListMessagesEn,
25
- ...portfolioProjectCardMessagesEn,
26
24
  ...portfolioProjectInfoMessagesEn,
27
25
  ...portfolioSmallCheckoutMessagesEn,
28
26
 
@@ -3,7 +3,6 @@ import { StoryFn, Meta } from '@storybook/react';
3
3
 
4
4
  import fpmProjectMock from '../../test/integrationMocks/fpmProjectMock';
5
5
  import { storybookStrapiAvatarMock } from '../../test/storybookMocks/storybookStrapiMedia';
6
- import CreditsAvailableState from '../../models/CreditsAvailableState';
7
6
  import ProjectFacts from '.';
8
7
 
9
8
  export default {
@@ -53,7 +52,7 @@ WithCheckout.args = {
53
52
 
54
53
  export const FullProps = Template.bind({});
55
54
  FullProps.args = {
56
- project: { ...fpmProjectMock, creditsAvailable: CreditsAvailableState.YES },
55
+ project: fpmProjectMock,
57
56
  slice: {
58
57
  projectId: fpmProjectMock.id,
59
58
 
@@ -0,0 +1,54 @@
1
+ import { render, screen } from '../../test/testUtils';
2
+ import { ProjectGridCardProps } from './ProjectGridCard';
3
+ import ProjectGridCard from '.';
4
+ import fpmProjectMock from '../../test/integrationMocks/fpmProjectMock';
5
+ import { strapiMediaMock } from '../../test/strapiMocks/strapiMedia';
6
+ import React from 'react';
7
+ import messagesEn from '../../components/CreditsAvailableBadge/messages.en';
8
+
9
+ const defaultProps: ProjectGridCardProps = {
10
+ project: {
11
+ ...fpmProjectMock,
12
+ slug: 'slug',
13
+ thumbnail: { img: { data: strapiMediaMock }, alt: 'Alt Text', id: 1 },
14
+ },
15
+ };
16
+
17
+ const setup = (props = {}) => {
18
+ const combinedProps = { ...defaultProps, ...props };
19
+ render(<ProjectGridCard {...combinedProps} />);
20
+ };
21
+
22
+ describe('The ProjectGridCard component', () => {
23
+ it('displays the project card', () => {
24
+ setup();
25
+
26
+ expect(screen.getByText(fpmProjectMock.title)).toBeInTheDocument();
27
+ });
28
+
29
+ it('displays the project thumbnail', () => {
30
+ setup();
31
+
32
+ expect(screen.getByRole('img')).toHaveProperty('alt', 'Alt Text');
33
+ });
34
+
35
+ it('displays the project area', () => {
36
+ setup();
37
+
38
+ expect(screen.getByText('140 ha')).toBeInTheDocument();
39
+ });
40
+
41
+ it('displays the project location', () => {
42
+ setup();
43
+
44
+ expect(screen.getByText('Austria')).toBeInTheDocument();
45
+ });
46
+
47
+ it('displays the credits available badge', () => {
48
+ setup();
49
+
50
+ expect(
51
+ screen.getByText(messagesEn['components.creditsAvailableBadge.text.yes'])
52
+ ).toBeInTheDocument();
53
+ });
54
+ });
@@ -0,0 +1,57 @@
1
+ import { Box, Container, Flex, Heading, Tag, Text } from 'boemly';
2
+ import React, { useContext } from 'react';
3
+ import Image from 'next/image';
4
+ import PortfolioProject from '../../models/PortfolioProject';
5
+ import { strapiMediaUrl } from '../..';
6
+ import { IntlContext } from 'react-intl';
7
+ import { FORMAT_AS_HECTARE_CONFIG } from '../../constants/formatter';
8
+ import CreditsAvailableBadge from '../../components/CreditsAvailableBadge';
9
+
10
+ export interface ProjectGridCardProps {
11
+ project: PortfolioProject;
12
+ }
13
+
14
+ export const ProjectGridCard = ({
15
+ project,
16
+ }: ProjectGridCardProps): JSX.Element => {
17
+ const { formatNumber } = useContext(IntlContext);
18
+
19
+ return (
20
+ <Container>
21
+ <Flex flexDir="column" height="full">
22
+ {project.thumbnail && (
23
+ <Box borderRadius="xl" position="relative" height="36" mb="2">
24
+ <Image
25
+ src={strapiMediaUrl(project.thumbnail?.img, 'medium')}
26
+ alt={project.thumbnail?.alt}
27
+ fill
28
+ style={{
29
+ objectFit: project.thumbnail?.objectFit || 'cover',
30
+ borderRadius: 'var(--boemly-radii-xl)',
31
+ }}
32
+ />
33
+ </Box>
34
+ )}
35
+ <Heading my="4" size="lg">
36
+ {project.title}
37
+ </Heading>
38
+ <Flex flexDir="row" gap="2">
39
+ <Tag>
40
+ <Text size="xsLowBold" color="gray.800">
41
+ {formatNumber(
42
+ (project.area || 0) / 10000,
43
+ FORMAT_AS_HECTARE_CONFIG
44
+ )}
45
+ </Text>
46
+ </Tag>
47
+ <Tag>
48
+ <Text size="xsLowBold" color="gray.800">
49
+ {project.location}
50
+ </Text>
51
+ </Tag>
52
+ </Flex>
53
+ <CreditsAvailableBadge status={project.creditAvailability} />
54
+ </Flex>
55
+ </Container>
56
+ );
57
+ };
@@ -0,0 +1,3 @@
1
+ import { ProjectGridCard } from './ProjectGridCard';
2
+
3
+ export default ProjectGridCard;
@@ -2,8 +2,8 @@ import React from 'react';
2
2
  import { StoryFn, Meta } from '@storybook/react';
3
3
 
4
4
  import ProjectsGrid from '.';
5
- import portfolioProjectMock from '../../test/integrationMocks/portfolioProjectMock';
6
5
  import { strapiProjectMock } from '../../test/strapiMocks/strapiProject';
6
+ import portfolioProjectMock from '../../test/integrationMocks/portfolioProjectMock';
7
7
 
8
8
  export default {
9
9
  title: 'slices/ProjectsGrid',
@@ -4,7 +4,6 @@ import ProjectsGrid from '.';
4
4
  import { ProjectsGridProps } from './ProjectsGrid';
5
5
  import fpmProjectMock from '../../test/integrationMocks/fpmProjectMock';
6
6
  import { strapiMediaMock } from '../../test/strapiMocks/strapiMedia';
7
- import CreditsAvailableState from '../../models/CreditsAvailableState';
8
7
  import { strapiProjectMock } from '../../test/strapiMocks/strapiProject';
9
8
 
10
9
  const defaultProps: ProjectsGridProps = {
@@ -18,7 +17,6 @@ const defaultProps: ProjectsGridProps = {
18
17
  isPublic: true,
19
18
  thumbnail: { img: { data: strapiMediaMock }, alt: 'Alt Text', id: 1 },
20
19
  footerSubTitle: 'certified-123',
21
- creditsAvailable: CreditsAvailableState.YES,
22
20
  },
23
21
  ],
24
22
  };
@@ -2,9 +2,11 @@ import React from 'react';
2
2
  import { Box, DefaultSectionContainer, SimpleGrid, Wrapper } from 'boemly';
3
3
  import Link from 'next/link';
4
4
  import { MEDIUM_TRANSITION_DURATION } from '../../constants/animations';
5
+ import ProjectGridCard from '../ProjectGridCard';
5
6
  import PortfolioProject from '../../models/PortfolioProject';
6
- import PortfolioProjectCard from '../../components/portfolio/PortfolioProjectCard';
7
- import { IStrapi, IStrapiData, StrapiProject } from '../..';
7
+ import IStrapi from '../../models/strapi/IStrapi';
8
+ import IStrapiData from '../../models/strapi/IStrapiData';
9
+ import StrapiProject from '../../models/strapi/StrapiProject';
8
10
 
9
11
  export interface ProjectsGridProps {
10
12
  slice: {
@@ -65,7 +67,7 @@ export const ProjectsGrid: React.FC<ProjectsGridProps> = ({
65
67
  transition={`box-shadow ease ${MEDIUM_TRANSITION_DURATION}s`}
66
68
  _hover={{ boxShadow: 'lg' }}
67
69
  >
68
- <PortfolioProjectCard project={project} />
70
+ <ProjectGridCard project={project} />
69
71
  </Box>
70
72
  </ConditionalWrapper>
71
73
  ))}
@@ -1,13 +1,14 @@
1
1
  import React from 'react';
2
2
  import { fireEvent, render, screen, waitFor } from '../../test/testUtils';
3
- import CreditsAvailableState from '../../models/CreditsAvailableState';
4
3
  import MapMarker, { MapMarkerProps } from './MapMarker';
5
4
  import messagesEn from './messages.en';
5
+ import { CreditAvailability } from '../../models/fpm/FPMProject';
6
6
 
7
7
  const defaultProps: MapMarkerProps = {
8
8
  title: 'Project title',
9
9
  portfolioHost: '',
10
10
  isPublic: true,
11
+ creditAvailability: CreditAvailability.CREDITS_AVAILABLE,
11
12
  };
12
13
 
13
14
  const setup = (props: Partial<MapMarkerProps> = {}) => {
@@ -88,7 +89,7 @@ describe('The MapMarker component', () => {
88
89
 
89
90
  it('renders the credit availability if it is defined', () => {
90
91
  setup({
91
- creditsAvailable: CreditsAvailableState.YES,
92
+ creditAvailability: CreditAvailability.CREDITS_AVAILABLE,
92
93
  });
93
94
 
94
95
  fireEvent.mouseEnter(screen.getByTestId('mapmarker-pin'));