diff --git a/main/coverage/clover.xml b/main/coverage/clover.xml
new file mode 100644
index 0000000000..048e118251
--- /dev/null
+++ b/main/coverage/clover.xml
@@ -0,0 +1,2088 @@
+
+
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 | 22x +22x +22x + + + + +75x + + +70x + +70x + +70x + +70x + +70x + + +70x + + + + + + + + + + + + +68x +68x +68x +63x +1x +1x +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +22x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import PropTypes from "prop-types"; +import Link from "next/link"; +import { useEffect } from "react"; + +/** + * Button component + */ +export function ActionButton(props) { + //Styling for buttons and links + const PRIMARY = + "text-multi-neutrals-white bg-multi-blue-blue70 hover:bg-multi-blue-blue60g focus:bg-multi-blue-blue60g"; + const SECONDARY = + "text-multi-blue-blue60b bg-multi-neutrals-grey30a hover:bg-multi-neutrals-grey50a focus:bg-multi-neutrals-grey60"; + const SUPERTASK = + "text-multi-neutrals-white bg-specific-green-green50 hover:bg-specific-green-green70 focus:bg-sepcific-green-green70"; + const DANGER = + "text-multi-neutrals-white bg-specific-red-red50 hover:bg-specific-red-red70 focus:bg-specific-red-red70"; + const LINK = + "text-multi-blue-blue60c hover:text-multi-blue-blue50b focus:text-multi-blue-blue60f"; + + const style = + props.style === "primary" + ? PRIMARY + : props.style === "secondary" + ? SECONDARY + : props.style === "supertask" + ? SUPERTASK + : props.style === "danger" + ? DANGER + : props.style === "link" + ? LINK + : ""; + + //Activate Links with spacebar + useEffect(() => { + let link = document.getElementById(props.id); + if (link) { + link.addEventListener("keydown", (event) => { + if (event.key === "Spacebar" || event.key === " ") { + event.preventDefault(); + link.click(); + } + }); + } + }); + + return props.href ? ( + <Link + href={props.href} + aria-label={`${props.ariaLabel ? props.ariaLabel : undefined}`} + className={`flex flex-row ${style} focus:ring focus:ring-offset-4 ring-multi-blue-blue60f py-2 px-4 rounded-sm w-fit text-base ${props.custom}`} + onClick={props.onClick} + id={props.id} + data-testid={props.dataTestId} + data-cy={props.dataCy || props.id} + data-cy-button={props.dataCyButton} + disabled={props.disabled} + role="button" + draggable="false" + lang={props.lang} + > + {props.icon && !props.iconEnd ? ( + <span className={props.icon} data-testid={props.dataTestId} /> + ) : undefined} + {props.text} + {props.children} + {props.icon && props.iconEnd ? ( + <span + className={`${props.icon} ${props.iconStyle}`} + data-testid={props.dataTestId} + /> + ) : undefined} + </Link> + ) : ( + <button + aria-expanded={`${props.ariaExpanded ? props.ariaExpanded : undefined}`} + aria-label={`${props.ariaLabel ? props.ariaLabel : undefined}`} + className={`flex flex-row ${style} focus:ring focus:ring-offset-4 ring-multi-blue-blue60f py-2 px-4 rounded-sm w-fit text-base ${props.custom}`} + onClick={props.onClick} + type={props.type} + id={props.id} + data-testid={props.dataTestId} + data-cy={props.dataCy || props.id} + data-cy-button={props.dataCyButton} + disabled={props.disabled} + data-gc-analytics-submit={props.analyticsTracking ? "submit" : undefined} + > + {props.icon && !props.iconEnd ? ( + <span className={props.icon} data-testid={props.dataTestId} /> + ) : undefined} + {props.imageSource && props.imageAlt ? ( + <> + <img src={props.imageSource} alt={props.imageAlt} /> + <span className={props.imageSpanClass} data-testid={props.dataTestId}> + {props.imageSpanText} + </span> + </> + ) : undefined} + <span className="flex"> + {props.text} + {props.expandIcon} + </span> + {props.children} + {props.icon && props.iconEnd ? ( + <span + className={`${props.icon} ${props.iconStyle}`} + data-testid={props.dataTestId} + /> + ) : undefined} + </button> + ); +} + +ActionButton.propTypes = { + /** + * This will add an icon inside the button when needed + */ + icon: PropTypes.string, + + /** + * This is for placing an icon at the end of the component + */ + iconEnd: PropTypes.bool, + + /** + * This will add styles to the icon span inside the button when needed + */ + iconStyle: PropTypes.string, + + /** + * The text that the button will display + */ + text: PropTypes.string, + + /** + * Style link as a button when there's a href + */ + href: PropTypes.string, + + /** + * Identify which button being clicked + */ + id: PropTypes.string.isRequired, + + /** + * Lang attribute for links that do not match the language of the top level document + */ + lang: PropTypes.string, + /** + * the type of the button + */ + type: PropTypes.oneOf(["submit", "reset"]), + + /** + * Secondary color styling option + */ + secondary: PropTypes.bool, + + /** + * Tertiary color styling option + */ + tertiary: PropTypes.bool, + + /** + * Custom button styling option + */ + custom: PropTypes.string, + + /** + * Callback for a click event on the button + */ + onClick: PropTypes.func, + + /** + * User must input one of the follow button styles to apply + * to their button. To apply the link style, the user must + * also add a value to the href prop + */ + style: PropTypes.oneOf([ + "supertask", + "primary", + "secondary", + "danger", + "link", + ]), + + /** + * any other elements you want to add to the button + */ + children: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.element, + PropTypes.arrayOf(PropTypes.element), + ]), + /** + * Test id for unit test + */ + dataTestId: PropTypes.string, + /** + * Test id for e2e test + */ + dataCy: PropTypes.string, + /** + * Test id for e2e test + */ + dataCyButton: PropTypes.string, + /** + * Enabled or disabled the button + */ + disabled: PropTypes.bool, + /** + * For tracking reset or submit on forms for analytics + */ + analyticsTracking: PropTypes.bool, + /** + * Expand icon that will show the Feedback as popup + */ + expandIcon: PropTypes.object, + /** + * Aria expanded state + */ + ariaExpanded: PropTypes.string, + /** + * Aria label + */ + ariaLabel: PropTypes.string, + /** + * Image source + */ + imageSource: PropTypes.string, + /** + * Image alt + */ + imageAlt: PropTypes.string, + /** + * Image span text + */ + imageSpanText: PropTypes.string, + /** + * Image span classname + */ + imageSpanClass: PropTypes.string, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 | 1x + +1x + + + + + + +5x +3x +3x +3x +5x + +1x + + + + + +1x + + + + + + +1x + + + + + + +1x + + + + + + +1x + + + + + + | import { ActionButton } from "./ActionButton";
+
+export default {
+ title: "Components/Atoms/ActionButton",
+ component: ActionButton,
+};
+
+const Template = (args) => <ActionButton {...args} />;
+
+export const Primary = Template.bind({});
+export const Secondary = Template.bind({});
+export const Supertask = Template.bind({});
+export const Danger = Template.bind({});
+export const Link = Template.bind({});
+
+Primary.args = {
+ id: "primary",
+ style: "primary",
+ text: "Primary",
+};
+
+Secondary.args = {
+ id: "secondary",
+ text: "Secondary",
+ style: "secondary",
+ secondary: true,
+};
+
+Supertask.args = {
+ id: "supertask",
+ text: "Supertask",
+ style: "supertask",
+ tertiary: true,
+};
+
+Danger.args = {
+ id: "danger",
+ text: "Danger",
+ style: "danger",
+ disabled: true,
+};
+
+Link.args = {
+ id: "link",
+ text: "Link",
+ style: "link",
+ href: "/",
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 | 1x +1x +1x + + + + + + + +3x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + | import PropTypes from "prop-types"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faCircleInfo } from "@fortawesome/free-solid-svg-icons"; +import { faTriangleExclamation } from "@fortawesome/free-solid-svg-icons"; + +/** + * Contextual alert component meant to draw attention to a short important message. + * Currently only has the option for an info alert, but other options can be added later so the alert + * can be customized. + */ +export function Alert(props) { + return ( + <div className="layout-container"> + <div + className={`relative border-l-6 min-h-40px my-10 ${ + props.triangle ? "border-[#EE7100]" : "border-[#269ABC]" + }`} + > + <span className="absolute py-1 top-4 -left-3.5 bg-white"> + {props.triangle ? ( + <FontAwesomeIcon + icon={faTriangleExclamation} + color={"#EE7100"} + size="xl" + /> + ) : ( + <FontAwesomeIcon icon={faCircleInfo} color={"#269ABC"} size="xl" /> + )} + </span> + <div className="ml-6"> + <h3 className="text-h3 font-display"> + <>{props.title}</> + </h3> + <p className="text-p">{props.text}</p> + </div> + </div> + </div> + ); +} + +Alert.propTypes = { + /** + * The title for the alert + */ + title: PropTypes.string, + /** + * The description for the alert, accepts a string or JSX + */ + text: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 | 1x + +1x + + + + + + +4x + +1x + + + + | import { Alert } from "./Alert";
+
+export default {
+ title: "Components/Atoms/Alert",
+ component: Alert,
+};
+
+const Template = (args) => <Alert {...args} />;
+
+export const Primary = Template.bind({});
+
+Primary.args = {
+ title: "Alert Title",
+ text: "Alert Text",
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 | 9x +9x + + + + + +9x + + + + + + + + + + + + + + + + + + + +9x + + + + + + + + + + + +9x + | import React from "react"; +import PropTypes from "prop-types"; + +/** + * Displays the banner on the page + */ + +export const Banner = ({ siteTitle, headline }) => { + return ( + <div className="bg-banner-img-mobile bg-center bg-cover py-8 sm:bg-banner-img sm:bg-right"> + <div className="lg:container xxs:mx-0 xxs:px-0 lg:mx-auto lg:px-6 xxl:mx-auto"> + <div className="bg-black bg-opacity-90 text-white p-4 xxs:w-screen lg:bg-opacity-30 lg:w-2/3 xl:w-1/2"> + <h1 + className="text-h1 font-medium pt-4 pb-2 break-words" + id="pageMainTitle" + tabIndex="-1" + > + {siteTitle} + </h1> + <hr className="border-2 border-hr-red-bar bg-hr-red-bar bg-opacity-90 border-opacity-90 w-3/4" /> + <p className="text-base font-normal py-4 break-words">{headline}</p> + </div> + </div> + </div> + ); +}; + +Banner.propTypes = { + /** + * Text area that displays the title for the page + */ + siteTitle: PropTypes.string.isRequired, + + /** + * text area for headline in the banner + */ + headline: PropTypes.string.isRequired, +}; + +export default Banner; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 | 1x +1x + +1x + + + + + + +4x + +1x + + + + | import React from "react";
+import Banner from "./Banner";
+
+export default {
+ title: "Components/Atoms/Banner",
+ component: Banner,
+};
+
+const Template = (args) => <Banner {...args} />;
+
+export const Primary = Template.bind({});
+
+Primary.args = {
+ siteTitle: "Banner Text",
+ headline: "Banner Headline",
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 | 9x +9x +9x +9x + + + + +16x + + + + + + + + + + + + + + +9x + + + + + + + + + + + + + + + + + + + + + + + + + +9x + + + + + + + + + + + + + + + + + + | import PropTypes from "prop-types"; +import Link from "next/link"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faChevronRight } from "@fortawesome/free-solid-svg-icons"; + +/** + * Breadcrumb component + */ +export function Breadcrumb(props) { + return ( + <nav aria-label="breadcrumbs"> + <ul className="block text-custom-blue-dark text-base font-body"> + <li className="inline-block min-w-0 max-w-full truncate px-1 ml-0"> + <Link + href="https://www.canada.ca/" + className="text-sm hover:text-custom-blue-link visited:text-purple-700 underline" + > + Canada.ca + </Link> + </li> + + {props.items + ? props.items.map((item, key) => { + return ( + <li + key={key} + className="inline-block min-w-0 max-w-full truncate px-1 ml-4" + > + <span className="inline-block mr-6"> + <FontAwesomeIcon + icon={faChevronRight} + className="text-xs text-gray-breadcrumb" + /> + </span> + <Link + href={item.link} + className="text-sm hover:text-canada-footer-hover-font-blue text-canada-footer-font visited:text-purple-700 underline" + > + {item.text} + </Link> + </li> + ); + }) + : null} + </ul> + </nav> + ); +} + +Breadcrumb.propTypes = { + /** + * Array of Items for the breadcrumb + */ + items: PropTypes.arrayOf( + PropTypes.shape({ + /** + * Text for the breadcrumb + */ + text: PropTypes.string, + + /** + * Link for the breadcrumb + */ + link: PropTypes.string, + }) + ), +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 | 1x + +1x + + + + + + +4x +3x + +1x + + + + + + + | import { Breadcrumb } from "./Breadcrumb";
+
+export default {
+ title: "Components/Atoms/Breadcrumb",
+ component: Breadcrumb,
+};
+
+const Template = (args) => <Breadcrumb {...args} />;
+
+export const Primary = Template.bind({});
+export const WithItems = Template.bind({});
+
+WithItems.args = {
+ items: [
+ { text: "Link1", link: "/" },
+ { text: "Link2", link: "/" },
+ { text: "Link3", link: "/" },
+ ],
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 | 4x + + + + +72x + + + + + +68x + + + + + + + + + + + + + + + + + +6x + + + + + + + + + + + + + + + + + + + + + + + + + + + + +4x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import PropTypes from "prop-types"; + +/** + * check box component for forms + */ +export function CheckBox({ + checked = false, + value = "true", + showRequiredLabel = false, + ...props +}) { + const ifControlledProps = !props.uncontrolled + ? { + checked: checked, + } + : {}; + return ( + <div + className={`block leading-tight relative pl-40px h-46px clear-left${ + props.className ? " " + props.className : " mb-4" + }`} + > + <input + className="control-input cursor-pointer appearance-none w-40px h-40px absolute left-0 m-0 z-1 opacity-0" + id={props.id} + name={props.name} + value={value} + type="checkbox" + onChange={(e) => + props.onChange( + props.uncontrolled ? !e.currentTarget.checked : checked, + props.name, + value + ) + } + aria-required={props.required} + aria-invalid={props.error ? "true" : undefined} + data-cy={props.dataCy} + data-testid={props.dataTestId} + {...ifControlledProps} + /> + <label + className={`checkbox-label control-label inline-block cursor-pointer pt-4px pb-5px px-15px text-sm lg:text-p leading-tight sm:leading-6 ${ + props.bolded ? "font-semibold" : "font-normal" + } font-body${props.error ? " text-error-border-red" : undefined}`} + htmlFor={props.id} + > + {showRequiredLabel ? ( + <b className="text-error-border-red" aria-hidden="true"> + * + </b> + ) : undefined}{" "} + {props.label} {<p className="sr-only">{props.expandState}</p>} + </label> + </div> + ); +} + +CheckBox.propTypes = { + /** + * additional css for the component + */ + className: PropTypes.string, + /** + * whether or not the checkbox is checked + */ + checked: PropTypes.bool.isRequired, + + /** + * the value of the field when the checkbox is checked + */ + value: PropTypes.string, + + /** + * the name of the checkbox + */ + name: PropTypes.string.isRequired, + + /** + * the id of the checkbox + */ + id: PropTypes.string.isRequired, + + /** + * the label for the checkbox + */ + label: PropTypes.string.isRequired, + + /** + * whether or not there is an error + */ + error: PropTypes.bool, + + /** + * whether or not the field is required + */ + required: PropTypes.bool, + + /** + * show the "* ... (required)" in the label. in lists, this isn't necessary, but for an individual checkbox without a parent fieldset this is required + */ + showRequiredLabel: PropTypes.bool, + + /** + * callback to handle change in checked state, takes three arguments, the checked state, the name and the value + */ + onChange: PropTypes.func, + + /** + * boolean flag to specify that this input should not be controlled by react + */ + uncontrolled: PropTypes.bool, + + /** + * boolean flag to specify when label content should be bolded + */ + bolded: PropTypes.bool, + + /** + * testing selector for cypress + */ + dataCy: PropTypes.string, + + /** + * testing selector for unit tests + */ + dataTestId: PropTypes.string, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 | 1x +1x + +1x + + + + + + + + + + + + + + + +7x +1x + + + + + + + +6x +1x + + + + + + + + +1x +1x + + + + + + + + +1x +1x + + + + + + + + | import React from "react"; +import { CheckBox } from "./CheckBox"; + +export default { + title: "Components/Atoms/CheckBox", + component: CheckBox, + decorators: [ + (Story) => ( + <div className="w-full flex justify-center"> + <div className="w-96"> + <Story /> + </div> + </div> + ), + ], +}; + +const Template = (args) => <CheckBox {...args} />; + +export const UnChecked = Template.bind({}); +UnChecked.args = { + id: "checkbox 1", + name: "ChexBox1", + value: "IsChecked", + label: "I am a checkbox", + dataTestId: "unchecked-checkbox", +}; + +export const Checked = Template.bind({}); +Checked.args = { + id: "checkbox 1", + name: "ChexBox1", + value: "IsChecked", + label: "I am a checkbox", + dataTestId: "checked-checkbox", + checked: true, +}; + +export const UnControlled = Template.bind({}); +UnControlled.args = { + id: "checkbox 1", + name: "ChexBox1", + value: "IsChecked", + label: "I am an uncontrolled checkbox", + dataTestId: "uncontrolled-checkbox", + uncontrolled: true, +}; + +export const Required = Template.bind({}); +Required.args = { + id: "checkbox 1", + name: "ChexBox1", + value: "IsChecked", + label: "I am an uncontrolled checkbox", + dataTestId: "required-checkbox", + showRequiredLabel: true, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 | 12x +12x + + + +11x + + + + + + + + +10x + +10x + +10x + +10x + +10x + +10x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +12x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import PropTypes from "prop-types"; +import { Image } from "./Image"; + +// Button used in HelpIcon.js and CTA.js +// Use ActionButton.js for all other buttons in the app +export function DSButton({ + id = "btn1", + styling = "supertask", + text = "default", + href = "no ref", + ...props +}) { + //Styling for buttons and links + const PRIMARY = + "text-multi-neutrals-white bg-multi-blue-blue70 hover:bg-multi-blue-blue60g focus:bg-multi-blue-blue60g"; + const SECONDARY = + "text-multi-blue-blue60b bg-multi-neutrals-grey30a hover:bg-multi-neutrals-grey50a focus:bg-multi-neutrals-grey60"; + const SUPERTASK = + "text-multi-neutrals-white bg-specific-green-green50 hover:bg-specific-green-green70 focus:bg-sepcific-green-green70"; + const DANGER = + "text-multi-neutrals-white bg-specific-red-red50 hover:bg-specific-red-red70 focus:bg-specific-red-red70"; + const LINK = + "text-multi-blue-blue60c hover:text-multi-blue-blue50b focus:text-multi-blue-blue60f"; + + styling = + styling === "primary" + ? PRIMARY + : styling === "secondary" + ? SECONDARY + : styling === "supertask" + ? SUPERTASK + : styling === "danger" + ? DANGER + : styling === "link" + ? LINK + : ""; + + return href === "no ref" ? ( + <button + className={`flex flex-row px-[16px] py-[8px] ${styling} rounded-sm focus:ring focus:ring-offset-4 ${props.className} `} + onClick={props.onClick} + type={props.type} + id={id} + disabled={props.disabled} + {...props.attributes} + alt={props.iconAltText} + > + {props.icon && !props.iconEnd ? ( + <span className="grid place-items-center h-8 w-8"> + <Image className="pr-2" src={props.icon} alt={props.iconAltText} /> + </span> + ) : undefined} + <span + className={`grid place-items-center ${ + styling === "supertask" ? "h-8" : "" + }`} + > + {text} + </span> + {props.children} + {props.icon && props.iconEnd ? ( + <span className="grid place-items-center h-8 w-8"> + <Image className="pl-2" src={props.icon} alt={props.iconAltText} /> + </span> + ) : undefined} + </button> + ) : ( + <a + href={href} + className={`flex flex-row ${ + styling !== "none" ? "btn-link" : "" + } focus:ring focus:ring-offset-4 ${props.className}`} + onClick={props.onClick} + id={id} + disabled={props.disabled} + role="button" + > + {props.icon && !props.iconEnd ? ( + <Image + className="h-8 w-8 pr-2" + src={props.icon} + alt={props.iconAltText} + /> + ) : undefined} + {text} + {props.children} + {props.icon && props.iconEnd ? ( + <div className="grid place-items-center h-8 w-8"> + <Image + className="pl-5 pb-3" + src={props.icon} + alt={props.iconAltText} + /> + </div> + ) : undefined} + </a> + ); +} + +DSButton.propTypes = { + /** + * Identify which button being clicked + */ + id: PropTypes.string.isRequired, + + /** + * User must input one of the follow button styles to apply + * to their button. To apply the link style, the user must + * also add a value to the href prop + */ + styling: PropTypes.oneOf([ + "supertask", + "primary", + "secondary", + "danger", + "link", + "none", + ]), + + /** + * The text that the button will display + */ + text: PropTypes.string.isRequired, + + /** + * This will add a img inside the button when needed + */ + icon: PropTypes.string, + + /** + * Alt text for icon added to button + */ + iconAltText: PropTypes.string, + + /** + * This is for placing an icon at the end of the component + */ + iconEnd: PropTypes.bool, + + /** + * Use when button redirects to a new page. + * Automatically applies the Link styling + */ + href: PropTypes.string, + + /** + * the type of the button + */ + type: PropTypes.oneOf(["submit", "reset", "button"]), + + /** + * Callback for a click event on the button + */ + onClick: PropTypes.func, + + /** + * bool to disable a button + */ + disabled: PropTypes.bool, + + /** + * css overrides for button + */ + className: PropTypes.string, + + /** + * additional attributes for button + */ + attributes: PropTypes.object, + + /** + * any other elements you want to add to the button + */ + children: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.element, + PropTypes.arrayOf(PropTypes.element), + ]), +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 | 1x + +1x + + + + + + +2x +1x +2x +2x +2x +2x + +1x + + + + + + +1x + + + + + + + + +1x + + + + + + +1x + + + + + + + +1x + + + + + + +1x + + + + + + + | import { DSButton } from "./DSButton"; + +export default { + title: "Components/Atoms/DSButton", + component: DSButton, +}; + +const Template = (args) => <DSButton {...args} />; + +export const Supertask = Template.bind({}); +export const SupertaskIcon = Template.bind({}); +export const Primary = Template.bind({}); +export const Secondary = Template.bind({}); +export const Danger = Template.bind({}); +export const Link = Template.bind({}); + +Supertask.args = { + id: "supertask", + styling: "supertask", + text: "Supertask button", + iconAltText: "supertask", +}; + +SupertaskIcon.args = { + id: "supertask_icon", + styling: "supertask", + text: "Supertask button", + icon: "plus.svg", + iconAltText: "icon", + iconEnd: false, +}; + +Primary.args = { + id: "primary", + text: "Primary button", + iconAltText: "prime", + styling: "primary", +}; + +Secondary.args = { + id: "secondary", + text: "Secondary Button", + iconEnd: false, + secondary: true, + styling: "secondary", +}; + +Danger.args = { + id: "danger", + text: "Danger Button", + iconEnd: false, + styling: "danger", +}; + +Link.args = { + id: "link", + text: "Link Button", + styling: "link", + href: "/", + iconAltText: "link", +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 | 9x +9x + +16x +15x + +15x +15x +9x +2x +7x + + + + + + + + + + + + + + + + +9x + + + + | import PropTypes from "prop-types"; +import { useTranslation } from "next-i18next"; + +export function DateModified({ date = process.env.NEXT_PUBLIC_BUILD_DATE }) { + const { t } = useTranslation("common"); + // TeamCity build dates are received in the format yyyyMMdd + let dateFormatted = "NA"; + if (date) { + if (!date.match(/(?=\S*['-])([a-zA-Z'-]+)/gm)) { + dateFormatted = date.replace(/^(.{4})(.{2})/gm, "$1-$2-"); + } else dateFormatted = date; + } + + return ( + <dl className="mt-8 py-2 font-body font-normal text-sm"> + <dt className="inline">{t("dateModified")}</dt> + <dd className="inline"> + {dateFormatted === "NA" ? ( + <time>{` ${dateFormatted}`}</time> + ) : ( + <time dateTime={dateFormatted}>{` ${dateFormatted}`}</time> + )} + </dd> + </dl> + ); +} + +DateModified.propTypes = { + // Date string in format yyyyMMdd + date: PropTypes.string, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 | 1x + +1x + + + + + + +5x + +1x + + + | import { DateModified } from "./DateModified";
+
+export default {
+ title: "Components/Atoms/DateModified",
+ component: DateModified,
+};
+
+const Template = (args) => <DateModified {...args} />;
+
+export const Primary = Template.bind({});
+
+Primary.args = {
+ date: "20200420",
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 | 16x + + + + +7x + + + + + + + + + +16x + + + + + + + + | import PropTypes from "prop-types"; + +/** + * error label component that is used with form inputs to display error messages + */ +export function ErrorLabel(props) { + return ( + <div + className={`error-label border-l-4 border-error-border-red px-3 py-1 bg-error-background-red font-body font-bold mb-5px text-sm lg:text-p ${props.className}`} + > + {props.message} + </div> + ); +} + +ErrorLabel.propTypes = { + message: PropTypes.string.isRequired, + + /** + * Prop for adding some classes + */ + className: PropTypes.string, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 | 1x +1x + +1x + + + + + + +5x +1x + + + | import React from "react";
+import { ErrorLabel } from "./ErrorLabel";
+
+export default {
+ title: "Components/Atoms/ErrorLabel",
+ component: ErrorLabel,
+};
+
+const Template = (args) => <ErrorLabel {...args} />;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ message: "Error 1: This is a message",
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 | 1x + +7x +7x +7x + +18x + +13x + + + + + + + + + + + +1x + + + + + + | import PropTypes from "prop-types"; + +export function HTMList({ tag = "ul", content, listClassName, liClassName }) { + const parseList = (content) => + content + .split("*") // split the string on asterisks + .filter((item) => item) // filter out empty strings + .map((item, index) => ( + <li className={liClassName} key={index}> + {item.trim()} + </li> + )); + + return tag === "ul" ? ( + <ul className={listClassName}>{parseList(content)}</ul> + ) : ( + <ol className={listClassName}>{parseList(content)}</ol> + ); +} + +HTMList.propTypes = { + tag: PropTypes.string, + content: PropTypes.string.isRequired, + listClassName: PropTypes.string, + liClassName: PropTypes.string, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 | 16x + +23x +23x + + + + + + + + +16x + + + + + + + + + + + + + + + + + + + + + + + + + + | import PropTypes from "prop-types"; + +export function Image(props) { + const { src, alt, rounded = "", className = "" } = props; + + return ( + <> + <img src={src} alt={alt} className={`${className} ${rounded}`} /> + </> + ); +} + +Image.propTypes = { + /** + * The text that the image tag will display + */ + id: PropTypes.string, + + /** + * Alternate text will be displayed in place of an image. + */ + alt: PropTypes.string, + + /** + * Identify source of image + */ + src: PropTypes.string.isRequired, + + /** + * css overrides for image + */ + className: PropTypes.string, + + /** + * Enables rounded corners for image + */ + rounded: PropTypes.string, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 | 1x + +1x + + + +1x +1x + + + +1x +1x +1x +1x + +1x + + + + + +1x + + + + + + +1x + + + + + +1x + + + + + + | import { Image } from "./Image";
+
+export default {
+ title: "Components/Atoms/Image",
+ component: Image,
+};
+import imageFile from "../../public/image1.png";
+import imageFile2 from "../../public/image2.png";
+
+const Template = (args) => <Image {...args} />;
+
+export const Default = Template.bind({});
+export const Mobile = Template.bind({});
+export const DefaultWithRounded = Template.bind({});
+export const MobileWithRounded = Template.bind({});
+
+Default.args = {
+ id: "image",
+ alt: "Default Image",
+ src: imageFile,
+};
+
+DefaultWithRounded.args = {
+ id: "image",
+ alt: "Default Image with rounded",
+ rounded: "rounded",
+ src: imageFile,
+};
+
+Mobile.args = {
+ id: "image",
+ alt: "Mobile Image",
+ src: imageFile2,
+};
+
+MobileWithRounded.args = {
+ id: "image",
+ alt: "Mobile Image with rounded",
+ rounded: "rounded",
+ src: imageFile2,
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 | +13x + + + +349x + +348x +348x + +1x + +1x + +1x + +1x + +66x + +66x + +273x + +273x + +1x + +1x + +1x + +1x + +5x + +5x + + +348x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +13x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | /* eslint-disable jsx-a11y/anchor-is-valid */ +import PropTypes from "prop-types"; + +// Use this component for Footer link and use Next.js <Link> +// for all links within the site +export function Link({ target = "_self", href = "#", ...props }) { + //Styling for links based on Figma Design + let basicStyle = ""; + switch (props.linkStyle) { + case "basicStyleWithEmphasis": + basicStyle = + "underline text-multi-blue-blue70b font-body text-browserh5 font-bold text-mobileh5 leading-33px hover:text-multi-blue-blue50b"; + break; + case "titleLink": + basicStyle = + "underline text-multi-blue-blue70b font-header text-browserh5 leading-23px font-bold hover:text-multi-blue-blue50b"; + break; + case "smfooterBlue": + basicStyle = + "text-multi-blue-blue70b font-body leading-20px text-browserh7 hover:underline"; + break; + case "smfooterWhite": + basicStyle = + "text-multi-neutrals-white font-body text-browserh7 leading-20px font-regular hover:text-multi-neutrals-white hover:underline focus:ring-1 focus:ring-white"; + break; + case "smBreadcrumbs": + basicStyle = + "text-multi-blue-blue70b font-body text-browserh8 leading-23px font-regular hover:text-multi-blue-blue50b"; + break; + case "cardActionLink": + basicStyle = + "text-multi-blue-blue70b font-body text-browserh5 underline leading-28px font-regular hover:text-multi-blue-blue50b"; + break; + default: + basicStyle = + "underline text-multi-blue-blue70b font-body text-browserh5 leading-33px hover:text-multi-blue-blue50b"; + break; + } + + const Component = props.component || "a"; + + function onKeyDown() { + true; + } + + return Component !== "a" ? ( + <Component + href={href} + disabled={props.disabled} + lang={props.lang} + target={target} + aria-label={props.ariaLabel || props.text} + role="link" + > + <a + href={href} + locale={props.locale} + onClick={props.onClick ? props.onClick : undefined} + id={props.id} + className={`${basicStyle}`} + data-gc-analytics-customclick={props.dataGcAnalyticsCustomClick} + onKeyDown={onKeyDown} + > + {/* <!-- English Text: English --> */} + <span className={props.abbr ? "language-toggle-text" : ""}> + {props.text} + </span> + {/* <!-- English Text: title="English", en --> */} + <abbr className="language-toggle-abbr" title={props.text}> + {props.abbr} + </abbr> + </a> + </Component> + ) : ( + <a + href={href} + className={`${basicStyle}`} + id={props.id} + disabled={props.disabled} + lang={props.lang} + target={target} + aria-label={props.ariaLabel || props.text} + locale={props.locale} + onClick={props.onClick ? props.onClick : undefined} + data-gc-analytics-customclick={props.dataGcAnalyticsCustomClick} + > + {/* <!-- English Text: English --> */} + <span className={props.abbr ? "language-toggle-text" : ""}> + {props.text} + </span> + {/* <!-- English Text: title="English", en --> */} + <abbr className="language-toggle-abbr" title={props.text}> + {props.abbr} + </abbr> + </a> + ); +} + +Link.propTypes = { + /** + * The text that Text Link will display + */ + text: PropTypes.string, + /** + * Abbrivation for text + */ + abbr: PropTypes.string, + /** + * Style link as a Text Link when there's a href + */ + href: PropTypes.string, + /** + * Target attribute to tell the browser where the linked document should be loaded. + */ + target: PropTypes.string, + /** + * Identify which Text Link being clicked + */ + id: PropTypes.string.isRequired, + /** + * Lang attribute for links that do not match the language of the top level document + */ + lang: PropTypes.string, + /** + * css overrides for Link + */ + className: PropTypes.string, + + /** + * For tracking on click of forms for analytics + */ + analyticsTracking: PropTypes.bool, + + /** + * use ariaLabel to provide more descriptive text for a link (screen reader friendly) + */ + ariaLabel: PropTypes.string, + + /** + * Allow user to use configurable component, default is html anchor tag + */ + component: PropTypes.elementType, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 | 1x + +1x + + + + + + +5x +3x +3x +3x +3x +3x + +1x + + + + + +1x + + + + + + +1x + + + + + + +1x + + + + + + +1x + + + + + + +1x + + + + + + | import { Link } from "./Link";
+
+export default {
+ title: "Components/Atoms/Link",
+ component: Link,
+};
+
+const Template = (args) => <Link {...args} />;
+
+export const Default = Template.bind({});
+export const RegularLinkwithEmphasis = Template.bind({});
+export const TitleLink = Template.bind({});
+export const FooterBlueLink = Template.bind({});
+export const BreadcrumbsLink = Template.bind({});
+export const CardActionLink = Template.bind({});
+
+Default.args = {
+ id: "link",
+ text: "Regular Link",
+ href: "/",
+};
+
+RegularLinkwithEmphasis.args = {
+ id: "link",
+ text: "Regular link with Emphasis",
+ href: "/",
+ linkStyle: "basicStyleWithEmphasis",
+};
+
+TitleLink.args = {
+ id: "link",
+ text: "Title Link",
+ href: "/",
+ linkStyle: "titleLink",
+};
+
+FooterBlueLink.args = {
+ id: "link",
+ text: "Small link - Footer blue",
+ href: "/",
+ linkStyle: "smfooterBlue",
+};
+
+BreadcrumbsLink.args = {
+ id: "link",
+ text: "Small link - Breadcrumbs & French toggle",
+ href: "/",
+ linkStyle: "smBreadcrumbs",
+};
+
+CardActionLink.args = {
+ id: "link",
+ text: "Card Action Link",
+ href: "/",
+ linkStyle: "cardActionLink",
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 | 3x +3x +3x + + + + +5x +4x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + + + +3x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import PropTypes from "prop-types"; +import { ErrorLabel } from "./ErrorLabel"; +import { useTranslation } from "next-i18next"; + +/** + * multi line text field + */ +export function MultiTextField({ spellCheck = true, wrap = "soft", ...props }) { + const { t } = useTranslation("common"); + + return ( + <div + className={`block leading-tight${ + props.className ? " " + props.className : " mb-12" + }`} + > + <label + className={`block leading-tight text-sm lg:text-p font-body mb-5px ${ + props.boldLabel ? "font-bold" : "" + }`} + htmlFor={props.id} + > + {props.required ? ( + <b className="text-error-border-red" aria-hidden="true"> + * + </b> + ) : undefined}{" "} + {props.label}{" "} + </label> + <p id={props.describedby} className="text-sm lg:text-g mb-5 leading-30px"> + {t("doNotInclude")} + </p> + {props.error ? <ErrorLabel message={props.error} /> : undefined} + <textarea + className={`text-input font-body w-full min-h-40px shadow-sm text-form-input-gray border-2 py-6px px-12px ${ + props.error ? "border-error-border-red" : "border-black" + }`} + id={props.id} + name={props.name} + placeholder={props.placeholder} + onChange={(e) => props.onChange(e.currentTarget.value)} + cols={props.cols} + rows={props.rows} + spellCheck={spellCheck} + wrap={wrap} + required={props.required} + data-testid={props.dataTestId} + data-cy={props.dataCy} + aria-describedby={props.describedby} + > + {props.value} + </textarea> + </div> + ); +} + +MultiTextField.propTypes = { + /** + * additional css for the component + */ + className: PropTypes.string, + + /** + * the id of the multi text field + */ + id: PropTypes.string.isRequired, + /** + * the name of the multi text field + */ + name: PropTypes.string.isRequired, + /** + * the label for the multi text field + */ + label: PropTypes.string.isRequired, + + /** + * the value for the multi text field + */ + value: PropTypes.string, + + /** + * message to display if there is an error + */ + error: PropTypes.string, + + /** + * whether or not the field is required + */ + required: PropTypes.bool, + + /** + * whether or not spellchecking is enabled for this field, by default it is + */ + spellCheck: PropTypes.bool, + + /** + * whether or not the label is bold + */ + boldLabel: PropTypes.bool, + /** + * whether to soft wrap or hard wrap the field + */ + wrap: PropTypes.oneOf(["soft", "hard"]), + /** + * the placeholder for the multi text field + */ + placeholder: PropTypes.string, + /** + * how much lines should the multi text field show + */ + rows: PropTypes.number, + /** + * how much columns should the multi text field show + */ + cols: PropTypes.number, + /** + * the minimum length of characters for the multi text field + */ + minLength: PropTypes.number, + /** + * the maximum length of characters for the multi text field + */ + maxLength: PropTypes.number, + /** + * call back for when the value of the multi text field changes + */ + onChange: PropTypes.func, + /** + * unit test selector + */ + dataTestId: PropTypes.string, + /** + * cypress selector + */ + dataCy: PropTypes.string, + + /** + * aria-describedby label id + */ + describedby: PropTypes.string, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 | 1x +1x + +1x + + + + + + + + + + + + + + + +4x +1x + + + + + + + +1x +1x + + + + + + + + +1x +1x + + + + + + + + + + | import React from "react"; +import { MultiTextField } from "./MultiTextField"; + +export default { + title: "Components/Atoms/MultiTextField", + component: MultiTextField, + decorators: [ + (Story) => ( + <div className="w-full flex justify-center"> + <div className="w-96"> + <Story /> + </div> + </div> + ), + ], +}; + +const Template = (args) => <MultiTextField i {...args} />; + +export const Primary = Template.bind({}); +Primary.args = { + id: "multiTextField1", + name: "multiTextField1", + label: "I am a multi text field", + dataTestId: "multitext-one", + placeholder: "some placeholder text", +}; + +export const BoldLabel = Template.bind({}); +BoldLabel.args = { + id: "multiTextField1", + name: "multiTextField1", + label: "I am a multi text field", + dataTestId: "multitext-bold", + placeholder: "some placeholder text", + boldLabel: true, +}; + +export const HardWrap = Template.bind({}); +HardWrap.args = { + id: "multiTextField1", + name: "multiTextField1", + label: "I am a multi text field", + dataTestId: "multitext-hard-wrap", + placeholder: "some placeholder text", + cols: 30, + rows: 5, + wrap: "hard", +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 | 7x +7x + +9x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +7x + + + + + + + + | import PropTypes from "prop-types"; +import { HelpIcon } from "../organisms/HelpIcon"; + +export function ProjectInfo(props) { + return ( + <> + <div className="grid grid-cols-1 xl:grid-cols-3 gap-x-2 text-[20px]"> + <strong className="font-body col-span-1">{props.termStarted}</strong> + <p className="col-span-2"> + {props.dateStarted && props.dateStarted.substring(0, 10)} + </p> + <strong className="font-body col-span-1">{props.termEnded}</strong> + <p className="col-span-2"> + {props.dateEnded && props.dateEnded.substring(0, 10)} + </p> + <strong className="font-body col-span-1 my-auto"> + {props.termStage} + </strong> + <div className="flex col-span-2 items-end"> + <div className="shrink-0 flex"> + <p className="my-auto">{props.stage}</p> + <div className="my-auto"> + <HelpIcon + lang={props.locale} + title={props.stage} + body={props.definition} + /> + </div> + </div> + </div> + <strong className="font-body col-span-1 col-start-1"> + {props.termSummary} + </strong> + <p className="col-span-2">{props.summary}</p> + </div> + </> + ); +} + +ProjectInfo.propTypes = { + dateStarted: PropTypes.string, + dateEnded: PropTypes.string, + stage: PropTypes.string, + summary: PropTypes.string, + info: PropTypes.string, + locale: PropTypes.string, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 | 1x + +1x + + + + + + +4x + +1x + + + + + + | import { ProjectInfo } from "./ProjectInfo";
+
+export default {
+ title: "Components/Atoms/ProjectInfo",
+ component: ProjectInfo,
+};
+
+const Template = (args) => <ProjectInfo {...args} />;
+
+export const Primary = Template.bind({});
+
+Primary.args = {
+ dateStarted: "2021-01-01",
+ dateEnded: "2022-03-31",
+ stage: "Alpha",
+ summary: "Project status",
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 | 2x + + + + +17x +16x + + + + + + + + + + + + + + + +3x + + +1x +1x +1x + + +1x + + + + + + + + + + + + + + + + + + + +2x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import PropTypes from "prop-types"; + +/** + * Radio input styled as a button + **/ +export function RadioButton({ checked = false, ...props }) { + const ifControlledProps = !props.uncontrolled + ? { + checked: checked, + } + : { + defaultChecked: checked || false, + }; + return ( + <div className="flex relative"> + <input + type="radio" + className="radio-button absolute top-0 left-0 w-full h-full appearance-none cursor-pointer" + id={props.id} + name={props.name} + value={props.value} + onChange={(e) => { + props.onChange(props.value, e); + }} + onKeyUp={(e) => { + if (e.key === "Enter") { + e.preventDefault(); + Iif (props.uncontrolled) { + e.currentTarget.checked = true; + } + props.onChange(props.value, e); + } + }} + data-testid={props.dataTestId} + data-cy={props.dataCy} + required={props.required} + {...ifControlledProps} + /> + <label + className={`radio-button-label font-body float-left text-xs px-5 py-3 border border-solid border-gray-600 border-opacity-50${ + props.roundedFront ? " rounded-l-lg" : "" + }${props.roundedBack ? " rounded-r-lg" : ""}`} + htmlFor={props.id} + > + {props.label} + </label> + </div> + ); +} + +RadioButton.propTypes = { + /** + * the id for the input + */ + id: PropTypes.string.isRequired, + + /** + * the name for the input + */ + name: PropTypes.string.isRequired, + + /** + * the value for the input + */ + value: PropTypes.string.isRequired, + + /** + * the label for the radio button + */ + label: PropTypes.string.isRequired, + + /** + * whether or not the field is required + */ + required: PropTypes.bool, + + /** + * whether the radio button is checked or not + */ + checked: PropTypes.bool, + + /** + * Should the button be rounded in the front + */ + roundedFront: PropTypes.bool, + + /** + * Should the button be rounded in the back + */ + roundedBack: PropTypes.bool, + + /** + * if the input is controlled by react or not + */ + uncontrolled: PropTypes.bool, + + /** + * onChange callback + */ + onChange: PropTypes.func, + + /** + * unit test selector + */ + dataTestId: PropTypes.string, + + /** + * cypress test selector + */ + dataCy: PropTypes.string, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 | 1x +1x + +1x + + + + + + +12x +1x + + + + + + + +2x +1x + + + + + + + + +3x +1x + + + + + + + + +3x +1x + + + + + + + + +3x +1x + + + + + + + + | import React from "react";
+import { RadioButton } from "./RadioButton";
+
+export default {
+ title: "Components/Atoms/RadioButton",
+ component: RadioButton,
+};
+
+const Template = (args) => <RadioButton {...args} />;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ id: "radio-button-1",
+ name: "radio_button_1",
+ value: "Some Value",
+ label: "My Radio Button",
+ dataTestId: "primary",
+};
+
+export const Checked = Template.bind({});
+Checked.args = {
+ id: "radio-button-checked",
+ name: "radio_button_checked",
+ value: "Some Value",
+ label: "My Radio Button",
+ dataTestId: "checked",
+ checked: true,
+};
+
+export const UnControlled = Template.bind({});
+UnControlled.args = {
+ id: "radio-button-uncontrolled",
+ name: "radio_button_uncontrolled",
+ value: "Some Value",
+ label: "My Radio Button",
+ dataTestId: "uncontrolled",
+ uncontrolled: true,
+};
+
+export const RoundedFront = Template.bind({});
+RoundedFront.args = {
+ id: "radio-button-rounded-front",
+ name: "radio_button_rounded_front",
+ value: "Some Value",
+ label: "My Radio Button",
+ dataTestId: "roundedFront",
+ roundedFront: true,
+};
+
+export const RoundedBack = Template.bind({});
+RoundedBack.args = {
+ id: "radio-button-rounded-back",
+ name: "radio_button_rounded_back",
+ value: "Some Value",
+ label: "My Radio Button",
+ dataTestId: "roundedBack",
+ roundedBack: true,
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 | 4x + + + + +10x +8x + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + + + + + + + + + + + + +4x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import PropTypes from "prop-types"; + +/** + * radio field + */ +export function RadioField({ checked = false, value = "true", ...props }) { + const ifControlledProps = !props.uncontrolled + ? { + checked: checked, + } + : {}; + return ( + <div + className={`block leading-tight relative pl-40px h-40px clear-left mb-10px${ + props.className ? " " + props.className : "" + }`} + > + <input + className="control-input cursor-pointer appearance-none w-40px h-40px absolute left-0 m-0 z-1 opacity-0" + id={props.id} + name={props.name} + value={value} + type="radio" + onChange={(e) => + props.onChange( + props.uncontrolled ? !e.currentTarget.checked : checked, + props.name, + value + ) + } + aria-required={props.required} + aria-invalid={props.error ? "true" : undefined} + data-cy={props.dataCy} + data-testid={props.dataTestId} + {...ifControlledProps} + /> + <label + className={`radio-field-label control-label inline-block cursor-pointer pt-4px pb-5px px-15px text-sm lg:text-p leading-tight sm:leading-6 font-normal font-body${ + props.error ? " text-error-border-red" : undefined + }`} + htmlFor={props.id} + onClick={() => props.onChange(checked, props.name, value)} + > + {props.label} + </label> + </div> + ); +} + +RadioField.propTypes = { + /** + * additional css for the component + */ + className: PropTypes.string, + /** + * whether or not the checkbox is checked + */ + checked: PropTypes.bool.isRequired, + + /** + * the value of the field when the checkbox is checked + */ + value: PropTypes.string, + + /** + * the name of the checkbox + */ + name: PropTypes.string.isRequired, + + /** + * whether or not there is an error + */ + error: PropTypes.bool, + + /** + * whether or not the field is required + */ + required: PropTypes.bool, + + /** + * the id of the checkbox + */ + id: PropTypes.string.isRequired, + + /** + * the label for the checkbox + */ + label: PropTypes.string.isRequired, + + /** + * callback to handle change in checked state, takes three arguments, the checked state, the name and the value + */ + onChange: PropTypes.func, + + /** + * boolean flag to specify that this input should not be controlled by react + */ + uncontrolled: PropTypes.bool, + + /** + * testing selector for cypress + */ + dataCy: PropTypes.string, + + /** + * testing selector for unit tests + */ + dataTestId: PropTypes.string, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 | 1x +1x + +1x + + + + + + + + + + + + + + + +7x +1x + + + + + + + +4x +1x + + + + + + + + +1x +1x + + + + + + + + | import React from "react"; +import { RadioField } from "./RadioField"; + +export default { + title: "Components/Atoms/RadioField", + component: RadioField, + decorators: [ + (Story) => ( + <div className="w-full flex justify-center"> + <div className="w-96"> + <Story /> + </div> + </div> + ), + ], +}; + +const Template = (args) => <RadioField {...args} />; + +export const UnChecked = Template.bind({}); +UnChecked.args = { + id: "radio 1", + name: "RadioField1", + value: "IsChecked", + label: "I am a radio button", + dataTestId: "unchecked-radio-field", +}; + +export const Checked = Template.bind({}); +Checked.args = { + id: "radio 1", + name: "RadioField1", + value: "IsChecked", + label: "I am a radio button", + dataTestId: "checked-radio-field", + checked: true, +}; + +export const UnControlled = Template.bind({}); +UnControlled.args = { + id: "radio 1", + name: "RadioField1", + value: "IsChecked", + label: "I am an uncontrolled checkbox", + dataTestId: "uncontrolled-checkbox", + uncontrolled: true, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 | 1x + + + + +3x + + + + + + + + + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + + + + + + + + + | import PropTypes from "prop-types"; + +/** + * component + */ +export function SearchBar(props) { + return ( + <form + className="w-full inline-flex h-9 lg:w-full xl:w-80 w-full border border-solid border-gray-light-100" + onSubmit={props.onSubmit} + data-cy={props.dataCy} + > + <input + type="text" + placeholder={props.placeholder} + className="placeholder-text-gray text-text-gray font-body py-1 px-2 focus:outline-none w-full" + onChange={props.onChange} + /> + + <button + title="Search bar button" + type="submit" + className={ + "bg-custom-blue-dark text-white text-center text-base rounded-none pt-0.5 h-full w-10 hover:bg-gray-dark active:bg-gray-dark focus:bg-gray-dark" + } + > + <span className="icon-search" /> + </button> + </form> + ); +} + +SearchBar.propTypes = { + /** + * Placeholder for the search bar + */ + placeholder: PropTypes.string.isRequired, + + /** + * Action to do on input change + */ + onChange: PropTypes.func, + + /** + * Action to do on form submit + */ + onSubmit: PropTypes.func, + + /** + * Test id for cypress test + */ + dataCy: PropTypes.string, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 | 1x + +1x + + + + + + +4x + +1x + + + | import { SearchBar } from "./SearchBar";
+
+export default {
+ title: "Components/Atoms/SearchBar",
+ component: SearchBar,
+};
+
+const Template = (args) => <SearchBar {...args} />;
+
+export const Primary = Template.bind({});
+
+Primary.args = {
+ placeholder: "Search Canada.ca",
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 | 1x +1x +1x + +4x +2x + +2x + + + + + +2x +2x +6x +6x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +8x + + + + + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import PropTypes from "prop-types"; +import { ErrorLabel } from "./ErrorLabel"; +import { useTranslation } from "next-i18next"; + +export function SelectField({ value = "", ...props }) { + const { t } = useTranslation("common"); + + const ifControlledProps = !props.uncontrolled + ? { + value: value, + } + : {}; + + if (!props.ignoreSort) { + props.options.sort(function (a, b) { + var collator = new Intl.Collator("fr"); + return collator.compare(a.name.toLowerCase(), b.name.toLowerCase()); + }); + } + + return ( + <div + className={`block leading-tight${ + props.className ? " " + props.className : " mb-10px" + }`} + > + <label + className={`select-field-label block leading-tight text-sm lg:text-p font-body mb-5 ${ + props.boldLabel ? "font-bold" : "" + }`} + htmlFor={props.id + "-choice"} + > + {props.required ? ( + <b className="text-error-border-red" aria-hidden="true"> + * + </b> + ) : undefined}{" "} + {props.label}{" "} + </label> + {props.error ? <ErrorLabel message={props.error} /> : undefined} + <select + className={`text-input select-field bg-white font-body w-full min-h-40px shadow-sm border-2 py-6px px-12px ${ + props.error ? "border-error-border-red" : "border-black" + }`} + id={props.id + "-choice"} + name={props.name} + aria-required={props.required} + aria-invalid={props.error ? "true" : undefined} + onChange={(e) => props.onChange(e.currentTarget.value)} + {...ifControlledProps} + data-testid={props.dataTestId + "-choice"} + data-cy={props.dataCy + "-choice"} + > + <option + key="default" + value="" + data-testid="default" + data-cy="default" + /> + {props.options.map(({ id, name, value }) => { + return ( + <option key={id} value={value} data-testid={id} data-cy={id}> + {name} + </option> + ); + })} + {props.other ? ( + <option + key={"other"} + value={"other"} + data-testid={"other"} + data-cy={"other"} + > + {t("reportAProblemOther")} + </option> + ) : ( + "" + )} + </select> + </div> + ); +} + +SelectField.propTypes = { + /** + * additional css for the component + */ + className: PropTypes.string, + + /** + * the id of the text field + */ + id: PropTypes.string.isRequired, + + /** + * the name of the text field + */ + name: PropTypes.string.isRequired, + + /** + * the label of the text field + */ + label: PropTypes.string.isRequired, + + /** + * whether ot not the field is required + */ + required: PropTypes.bool, + + /** + * value of the text field + */ + value: PropTypes.string.isRequired, + + /** + * call back for when the value of the text field changes + */ + onChange: PropTypes.func, + + /** + * message to display if there is an error + */ + error: PropTypes.string, + + /** + * Other option for dropdown + */ + other: PropTypes.bool, + + /** + * if label should be bold + */ + boldLabel: PropTypes.bool, + + /** + * boolean flag to specify that this input should be uncontrolled by react + */ + uncontrolled: PropTypes.bool, + + options: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + value: PropTypes.string.isRequired, + }) + ), + + /** + * unit test selector + */ + dataTestId: PropTypes.string, + + /** + * cypress tests selector + */ + dataCy: PropTypes.string, + + /** + * if true, skip sorting the options + */ + ignoreSort: PropTypes.bool, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 | 1x +1x + +1x + + + + + + + + + + + + + + + +4x +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import React from "react";
+import { SelectField } from "./SelectField";
+
+export default {
+ title: "Components/Atoms/SelectField",
+ component: SelectField,
+ decorators: [
+ (Story) => (
+ <div className="w-full flex justify-center">
+ <div className="w-96">
+ <Story />
+ </div>
+ </div>
+ ),
+ ],
+};
+
+const Template = (args) => <SelectField {...args} />;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ id: "select-field-1",
+ name: "selectField1",
+ label: "I am a select field",
+ uncontrolled: true,
+ dataTestId: "select-field-1",
+ options: [
+ {
+ id: "option1",
+ name: "Option 1",
+ value: "option1",
+ },
+ {
+ id: "option2",
+ name: "Option 2",
+ value: "option2",
+ },
+ {
+ id: "option3",
+ name: "Option 3",
+ value: "option3",
+ },
+ {
+ id: "option4",
+ name: "Option 4",
+ value: "option4",
+ },
+ ],
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 | 1x + +3x + + + + + + +2x + + + + + + + + + + + + + + +1x + + + + + + + + + + | import PropTypes from "prop-types"; + +export function TableOfContents(props) { + return ( + <> + <h2 className="font-semibold">{props.title}</h2> + <nav> + <ul className="leading-4 list-disc"> + {props.headings.map((heading) => ( + <li key={heading.id}> + <a + className="underline text-custom-blue-link underline hover:text-custom-blue-projects-link" + href={`#${heading.id}`} + > + {heading.text} + </a> + </li> + ))} + </ul> + </nav> + </> + ); +} + +TableOfContents.propTypes = { + /** + * The title for the table of contents + */ + title: PropTypes.string, + /** + * An array of headings + */ + headings: PropTypes.array, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 | 1x + +1x + + + + + + +4x + +1x + + + + | import { TableOfContents } from "./TableOfContents";
+
+export default {
+ title: "Components/Atoms/TableOfContents",
+ component: TableOfContents,
+};
+
+const Template = (args) => <TableOfContents {...args} />;
+
+export const Primary = Template.bind({});
+
+Primary.args = {
+ title: "Table of Contents Title",
+ headings: [{ id: "heading-one", text: "Heading one" }],
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 | 3x +3x +3x + + + + +7x +6x + +6x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +2x + + + + + + + + +3x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import PropTypes from "prop-types"; +import { ErrorLabel } from "./ErrorLabel"; +import { useTranslation } from "next-i18next"; + +/** + * text field component + */ +export function TextField({ value = "", type = "text", ...props }) { + const { t } = useTranslation("common"); + + const ifControlledProps = !props.uncontrolled + ? { + value: value, + } + : {}; + return ( + <div + className={`block leading-tight${ + props.className ? " " + props.className : " mb-10px" + }`} + > + <label + className={`block leading-tight text-sm lg:text-p font-body mb-5 ${ + props.boldLabel ? "font-bold" : "" + }`} + htmlFor={props.id} + > + {props.required ? ( + <b className="text-error-border-red" aria-hidden="true"> + * + </b> + ) : undefined}{" "} + {props.label}{" "} + </label> + {props.describedby ? ( + <p + id={props.describedby} + className="text-xs lg:text-sm mb-5 leading-30px" + > + {t("doNotInclude")} + </p> + ) : ( + "" + )} + + {props.error ? <ErrorLabel message={props.error} /> : undefined} + <input + className={`text-input font-body w-full lg:w-3/4 min-h-40px shadow-sm text-form-input-gray border-2 py-6px px-12px ${ + props.error ? "border-error-border-red" : "border-black" + } ${props.exclude ? "exclude" : ""}`} + id={props.id} + aria-describedby={props.describedby} + name={props.name} + placeholder={props.placeholder} + type={type} + min={props.min} + max={props.max} + step={props.step} + aria-required={props.required} + aria-invalid={props.error ? "true" : undefined} + onChange={(e) => props.onChange(e.currentTarget.value)} + {...ifControlledProps} + data-testid={props.dataTestId} + data-cy={props.dataCy} + autoComplete={props.autoComplete} + /> + </div> + ); +} +TextField.propTypes = { + /** + * additional css for the component + */ + className: PropTypes.string, + + /** + * the id of the text field + */ + id: PropTypes.string.isRequired, + + /** + * the name of the text field + */ + name: PropTypes.string.isRequired, + + /** + * the label of the text field + */ + label: PropTypes.string.isRequired, + + /** + * whether ot not the field is required + */ + required: PropTypes.bool, + + /** + * value of the text field + */ + value: PropTypes.string, + + /** + * placeholder for the text field, + */ + placeholder: PropTypes.string, + + /** + * the type of the input + */ + type: PropTypes.string, + + /** + * call back for when the value of the text field changes + */ + onChange: PropTypes.func, + + /** + * message to display if there is an error + */ + error: PropTypes.string, + + /** + * if label should be bold + */ + boldLabel: PropTypes.bool, + + /** + * boolean flag to specify that this input should be uncontrolled by react + */ + uncontrolled: PropTypes.bool, + + /** + * min value allowed + */ + min: PropTypes.number, + + /** + * max value allowed + */ + max: PropTypes.number, + + /** + * the legal number of intervals + */ + step: PropTypes.number, + + /** + * unit test selector + */ + dataTestId: PropTypes.string, + + /** + * cypress tests selector + */ + dataCy: PropTypes.string, + + /** + * Exclude option for adding exclude class to the textfield + */ + exclude: PropTypes.bool, + + /** + * aria-describedby label id + */ + describedby: PropTypes.string, + + /** + * Option to enable autocomplete on field + */ + autocomplete: PropTypes.string, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 | 1x +1x + +1x + + + + + + + + + + + + + + + +4x +1x + + + + + + + +2x +1x + + + + + + + + +3x +1x + + + + + + + + + | import React from "react";
+import { TextField } from "./TextField";
+
+export default {
+ title: "Components/Atoms/TextField",
+ component: TextField,
+ decorators: [
+ (Story) => (
+ <div className="w-full flex justify-center">
+ <div className="w-96">
+ <Story />
+ </div>
+ </div>
+ ),
+ ],
+};
+
+const Template = (args) => <TextField {...args} />;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ id: "textField1",
+ name: "textField1",
+ label: "I am a text field",
+ dataTestId: "textbox-controlled",
+ placeholder: "Some placeholder text",
+};
+
+export const UnControlled = Template.bind({});
+UnControlled.args = {
+ id: "textField1",
+ name: "textField1",
+ label: "I am a text field",
+ placeholder: "Some placeholder text",
+ dataTestId: "textbox-uncontrolled",
+ uncontrolled: true,
+};
+
+export const BoldLabel = Template.bind({});
+BoldLabel.args = {
+ id: "textField1",
+ name: "textField1",
+ label: "I am a text field",
+ placeholder: "Some placeholder text",
+ dataTestId: "textbox-bold",
+ uncontrolled: true,
+ boldLabel: true,
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +File | ++ | Statements | ++ | Branches | ++ | Functions | ++ | Lines | ++ |
---|---|---|---|---|---|---|---|---|---|
ActionButton.js | +
+
+ |
+ 100% | +18/18 | +85.1% | +40/47 | +100% | +3/3 | +100% | +18/18 | +
ActionButton.stories.js | +
+
+ |
+ 94.44% | +17/18 | +100% | +0/0 | +100% | +0/0 | +100% | +12/12 | +
Alert.js | +
+
+ |
+ 100% | +5/5 | +33.33% | +1/3 | +100% | +1/1 | +100% | +5/5 | +
Alert.stories.js | +
+
+ |
+ 83.33% | +5/6 | +100% | +0/0 | +100% | +0/0 | +100% | +4/4 | +
Banner.js | +
+
+ |
+ 100% | +7/7 | +100% | +0/0 | +100% | +1/1 | +100% | +5/5 | +
Banner.stories.js | +
+
+ |
+ 85.71% | +6/7 | +100% | +0/0 | +100% | +0/0 | +100% | +5/5 | +
Breadcrumb.js | +
+
+ |
+ 100% | +7/7 | +100% | +2/2 | +100% | +2/2 | +100% | +7/7 | +
Breadcrumb.stories.js | +
+
+ |
+ 87.5% | +7/8 | +100% | +0/0 | +100% | +0/0 | +100% | +5/5 | +
CheckBox.js | +
+
+ |
+ 100% | +5/5 | +76.47% | +13/17 | +100% | +2/2 | +100% | +5/5 | +
CheckBox.stories.js | +
+
+ |
+ 81.25% | +13/16 | +100% | +0/0 | +100% | +0/0 | +100% | +11/11 | +
DSButton.js | +
+
+ |
+ 100% | +10/10 | +62.85% | +22/35 | +100% | +1/1 | +100% | +10/10 | +
DSButton.stories.js | +
+
+ |
+ 90.47% | +19/21 | +100% | +0/0 | +100% | +0/0 | +100% | +14/14 | +
DateModified.js | +
+
+ |
+ 100% | +10/10 | +100% | +5/5 | +100% | +1/1 | +100% | +10/10 | +
DateModified.stories.js | +
+
+ |
+ 83.33% | +5/6 | +100% | +0/0 | +100% | +0/0 | +100% | +4/4 | +
ErrorLabel.js | +
+
+ |
+ 100% | +3/3 | +100% | +0/0 | +100% | +1/1 | +100% | +3/3 | +
ErrorLabel.stories.js | +
+
+ |
+ 85.71% | +6/7 | +100% | +0/0 | +100% | +0/0 | +100% | +5/5 | +
HTMList.js | +
+
+ |
+ 100% | +7/7 | +100% | +2/2 | +100% | +4/4 | +100% | +7/7 | +
Image.js | +
+
+ |
+ 100% | +4/4 | +100% | +2/2 | +100% | +1/1 | +100% | +4/4 | +
Image.stories.js | +
+
+ |
+ 94.11% | +16/17 | +100% | +0/0 | +100% | +0/0 | +100% | +12/12 | +
Link.js | +
+
+ |
+ 95.23% | +20/21 | +62.5% | +15/24 | +50% | +1/2 | +95.23% | +20/21 | +
Link.stories.js | +
+
+ |
+ 95.23% | +20/21 | +100% | +0/0 | +100% | +0/0 | +100% | +14/14 | +
MultiTextField.js | +
+
+ |
+ 100% | +7/7 | +66.66% | +8/12 | +100% | +2/2 | +100% | +7/7 | +
MultiTextField.stories.js | +
+
+ |
+ 76.92% | +10/13 | +100% | +0/0 | +100% | +0/0 | +100% | +9/9 | +
ProjectInfo.js | +
+
+ |
+ 100% | +4/4 | +100% | +4/4 | +100% | +1/1 | +100% | +4/4 | +
ProjectInfo.stories.js | +
+
+ |
+ 83.33% | +5/6 | +100% | +0/0 | +100% | +0/0 | +100% | +4/4 | +
RadioButton.js | +
+
+ |
+ 90% | +9/10 | +90.9% | +10/11 | +100% | +3/3 | +90% | +9/10 | +
RadioButton.stories.js | +
+
+ |
+ 94.73% | +18/19 | +100% | +0/0 | +100% | +0/0 | +100% | +13/13 | +
RadioField.js | +
+
+ |
+ 83.33% | +5/6 | +58.33% | +7/12 | +66.66% | +2/3 | +83.33% | +5/6 | +
RadioField.stories.js | +
+
+ |
+ 84.61% | +11/13 | +100% | +0/0 | +100% | +0/0 | +100% | +9/9 | +
SearchBar.js | +
+
+ |
+ 100% | +3/3 | +100% | +0/0 | +100% | +1/1 | +100% | +3/3 | +
SearchBar.stories.js | +
+
+ |
+ 83.33% | +5/6 | +100% | +0/0 | +100% | +0/0 | +100% | +4/4 | +
SelectField.js | +
+
+ |
+ 92.3% | +12/13 | +55.55% | +10/18 | +75% | +3/4 | +92.3% | +12/13 | +
SelectField.stories.js | +
+
+ |
+ 85.71% | +6/7 | +100% | +0/0 | +100% | +0/0 | +100% | +5/5 | +
TableOfContents.js | +
+
+ |
+ 100% | +4/4 | +100% | +0/0 | +100% | +2/2 | +100% | +4/4 | +
TableOfContents.stories.js | +
+
+ |
+ 83.33% | +5/6 | +100% | +0/0 | +100% | +0/0 | +100% | +4/4 | +
TextField.js | +
+
+ |
+ 100% | +8/8 | +65% | +13/20 | +100% | +2/2 | +100% | +8/8 | +
TextField.stories.js | +
+
+ |
+ 92.3% | +12/13 | +100% | +0/0 | +100% | +0/0 | +100% | +9/9 | +
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 | 3x +3x +3x +3x +3x +3x +3x +3x + +3x + + + + + + + + +3x +16x + +1x + + + + + + + + + + + + + + + + + + + + + + + + + +2x + +1x + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + + +6x + + + + + + + +5x + + + + + + + + + + +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +10x + + +10x +16x +16x + + +16x + + + + + + + + + + + +9x + + | import { v4 as uuid } from "uuid"; +import TextWithImage from "./fragment_components/TextWithImage"; +import TextContent from "./fragment_components/TextContent"; +import Button from "./fragment_components/Button"; +import ArticleCTA from "./fragment_components/ArticleCTA"; +import QuoteVerticalLineContent from "./fragment_components/QuoteVerticalLineContent"; +import ImageWithCollapse from "./fragment_components/ImageWithCollapse"; +import TextRender from "../text_node_renderer/TextRender"; + +const FRAGMENTS = { + "SCLabs-Comp-Content-Image-v1": TextWithImage, + "SCLabs-Comp-Content-v1": QuoteVerticalLineContent, + "SCLabs-Content-v1": TextContent, + "SCLabs-Button-v1": Button, + "SCLabs-Feature-v1": ArticleCTA, + "SCLabs-Image-v1": ImageWithCollapse, +}; + +const mapFragmentsToProps = (fragmentData, fragmentName, locale) => { + switch (fragmentName) { + case "SCLabs-Feature-v1": + return { + heading: + locale === "en" ? fragmentData.scTitleEn : fragmentData.scTitleFr, + body: ( + <TextRender + data={ + locale === "en" + ? fragmentData.scContentEn.json + : fragmentData.scContentFr.json + } + /> + ), + ButtonProps: { + id: fragmentData.scLabsButton[0].scId, + text: + locale === "en" + ? fragmentData.scLabsButton[0].scTitleEn + : fragmentData.scLabsButton[0].scTitleFr, + href: + locale === "en" + ? fragmentData.scLabsButton[0].scDestinationURLEn + : fragmentData.scLabsButton[0].scDestinationURLFr, + }, + }; + + case "SCLabs-Comp-Content-Image-v1": + switch (fragmentData.scLabLayout) { + case "default": + return { + src: + locale === "en" + ? fragmentData.scLabImage.scImageEn._publishUrl + : fragmentData.scLabImage.scImageFr._publishUrl, + alt: fragmentData.scLabImage.scImageAltTextEn + ? locale === "en" + ? fragmentData.scLabImage.scImageAltTextEn + : fragmentData.scLabImage.scImageAltTextFr + : "", + width: fragmentData.scLabImage.scImageEn.width, + height: fragmentData.scLabImage.scImageEn.height, + data: + locale === "en" + ? fragmentData.scLabContent[0].scContentEn.json + : fragmentData.scLabContent[0].scContentFr.json, + layout: fragmentData.scLabLayout, + }; + case "image-vertical-line-content": + return { + src: + locale === "en" + ? fragmentData.scLabImage.scImageEn._publishUrl + : fragmentData.scLabImage.scImageFr._publishUrl, + alt: fragmentData.scLabImage.scImageAltTextEn + ? locale === "en" + ? fragmentData.scLabImage.scImageAltTextEn + : fragmentData.scLabImage.scImageAltTextFr + : "", + width: fragmentData.scLabImage.scImageEn.width, + height: fragmentData.scLabImage.scImageEn.height, + data: + locale === "en" + ? fragmentData.scLabContent[0].scContentEn.json + : fragmentData.scLabContent[0].scContentFr.json, + layout: fragmentData.scLabLayout, + title: + locale === "en" + ? fragmentData.scLabImage.scLongDescHeadingEn + : fragmentData.scLabImage.scLongDescHeadingFr, + longDesc: + locale === "en" + ? fragmentData.scLabImage.scLongDescEn + : fragmentData.scLabImage.scLongDescFr, + children: ( + <TextRender + data={ + locale === "en" + ? fragmentData.scLabImage.scLongDescEn?.json + : fragmentData.scLabImage.scLongDescFr?.json + } + /> + ), + }; + default: + break; + } + + case "SCLabs-Comp-Content-v1": + return { + quoteText: + locale === "en" + ? fragmentData.scLabContent[0].scContentEn.json + : fragmentData.scLabContent[0].scContentFr.json, + explanationtext: + locale === "en" + ? fragmentData.scLabContent[1].scContentEn.json + : fragmentData.scLabContent[1].scContentFr.json, + }; + + case "SCLabs-Content-v1": + return { + data: + locale === "en" + ? fragmentData.scContentEn.json + : fragmentData.scContentFr.json, + }; + + case "SCLabs-Button-v1": + return { + id: fragmentData.scId, + buttonType: fragmentData.scButtonType[0], + href: + locale === "en" + ? fragmentData.scDestinationURLEn + : fragmentData.scDestinationURLFr, + text: locale === "en" ? fragmentData.scTitleEn : fragmentData.scTitleFr, + }; + + case "SCLabs-Image-v1": + return { + id: fragmentData.scId, + src: + locale === "en" + ? fragmentData.scImageEn._publishUrl + : fragmentData.scImageFr._publishUrl, + alt: + locale === "en" + ? fragmentData.scImageAltTextEn + : fragmentData.scImageAltTextFr, + width: fragmentData.scImageEn.width, + height: fragmentData.scImageEn.height, + content: + locale === "en" + ? fragmentData.scImageCaptionEn.json[0].content[0].value + : fragmentData.scImageCaptionFr.json[0].content[0].value, + title: + locale === "en" + ? fragmentData.scLongDescHeadingEn + : fragmentData.scLongDescHeadingFr, + longDesc: + locale === "en" + ? fragmentData.scLongDescEn + : fragmentData.scLongDescFr, + children: ( + <TextRender + data={ + locale === "en" + ? fragmentData.scLongDescEn.json + : fragmentData.scLongDescFr.json + } + /> + ), + }; + default: + break; + } +}; + +export default function FragmentRender(props) { + // Create and return array of elements corresponding to + // fragments + const pageFragments = props.fragments.map((fragmentData) => { + const Fragment = FRAGMENTS[fragmentData?._model.title]; + Iif (!Fragment) { + return; + } + return ( + <Fragment + key={uuid()} + {...mapFragmentsToProps( + fragmentData, + fragmentData?._model.title, + props.locale + )} + /> + ); + }); + + return pageFragments; +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 +484 +485 +486 +487 +488 +489 +490 +491 +492 +493 +494 +495 +496 +497 +498 +499 +500 +501 +502 +503 +504 +505 +506 +507 +508 +509 +510 +511 +512 +513 +514 +515 +516 +517 +518 +519 +520 +521 +522 +523 +524 +525 +526 +527 +528 +529 +530 +531 +532 +533 +534 +535 +536 +537 +538 +539 +540 +541 +542 +543 +544 +545 +546 +547 +548 +549 +550 +551 +552 +553 +554 +555 +556 +557 +558 +559 +560 +561 +562 +563 +564 +565 +566 +567 +568 +569 +570 +571 +572 +573 +574 +575 +576 +577 +578 +579 +580 +581 +582 +583 +584 +585 +586 +587 +588 +589 +590 +591 +592 +593 +594 +595 +596 +597 +598 +599 +600 +601 +602 +603 +604 +605 +606 +607 +608 +609 +610 +611 +612 +613 +614 +615 +616 +617 +618 +619 +620 +621 +622 +623 +624 +625 +626 +627 +628 +629 +630 +631 +632 +633 +634 +635 +636 +637 +638 +639 +640 +641 +642 +643 +644 +645 +646 +647 +648 +649 +650 +651 +652 +653 +654 +655 +656 +657 +658 +659 +660 +661 +662 +663 +664 +665 +666 +667 +668 +669 +670 +671 +672 +673 +674 +675 +676 +677 +678 +679 +680 +681 +682 +683 +684 +685 +686 +687 +688 +689 +690 +691 +692 +693 +694 +695 +696 +697 +698 +699 +700 +701 +702 +703 +704 +705 +706 +707 +708 +709 +710 +711 +712 +713 +714 +715 +716 +717 +718 +719 +720 +721 +722 +723 +724 +725 +726 +727 +728 +729 +730 +731 +732 +733 +734 +735 +736 +737 +738 +739 +740 +741 +742 +743 +744 +745 +746 +747 +748 +749 +750 +751 +752 +753 +754 +755 +756 +757 +758 +759 +760 +761 +762 +763 +764 +765 +766 +767 +768 +769 +770 +771 +772 +773 +774 +775 +776 +777 +778 +779 +780 +781 +782 +783 +784 +785 +786 +787 +788 +789 +790 +791 +792 +793 +794 +795 +796 +797 +798 +799 +800 +801 +802 +803 +804 +805 +806 +807 +808 +809 +810 +811 +812 +813 +814 +815 +816 +817 +818 +819 +820 +821 +822 +823 +824 +825 +826 +827 +828 +829 +830 +831 +832 +833 +834 +835 +836 +837 +838 +839 +840 +841 +842 +843 +844 +845 +846 +847 +848 +849 +850 +851 +852 +853 +854 +855 +856 +857 +858 +859 +860 +861 +862 +863 +864 +865 +866 +867 +868 +869 +870 +871 +872 +873 +874 +875 +876 +877 +878 +879 +880 +881 +882 +883 +884 +885 +886 +887 +888 +889 +890 +891 +892 +893 +894 +895 +896 +897 +898 +899 +900 +901 +902 +903 +904 +905 +906 +907 +908 +909 +910 +911 +912 +913 +914 +915 +916 +917 +918 +919 +920 +921 +922 +923 +924 +925 +926 +927 +928 +929 +930 +931 +932 +933 +934 +935 +936 +937 +938 +939 +940 +941 +942 +943 +944 +945 +946 +947 +948 +949 +950 +951 +952 +953 +954 +955 +956 +957 +958 +959 +960 +961 +962 +963 +964 +965 +966 +967 +968 +969 +970 +971 +972 +973 +974 +975 +976 +977 +978 +979 +980 +981 +982 +983 +984 +985 +986 +987 +988 +989 +990 +991 +992 +993 +994 +995 +996 +997 +998 +999 +1000 +1001 +1002 +1003 +1004 +1005 +1006 +1007 +1008 +1009 +1010 +1011 +1012 +1013 +1014 +1015 +1016 +1017 +1018 +1019 +1020 +1021 +1022 +1023 +1024 +1025 +1026 +1027 +1028 +1029 +1030 +1031 +1032 +1033 +1034 +1035 +1036 +1037 +1038 +1039 +1040 +1041 +1042 +1043 +1044 +1045 +1046 +1047 +1048 +1049 +1050 +1051 +1052 +1053 +1054 +1055 +1056 +1057 +1058 +1059 +1060 +1061 +1062 +1063 +1064 +1065 +1066 +1067 +1068 +1069 +1070 +1071 +1072 +1073 +1074 +1075 +1076 +1077 +1078 +1079 +1080 +1081 +1082 +1083 +1084 +1085 +1086 +1087 +1088 +1089 +1090 +1091 +1092 +1093 +1094 +1095 +1096 +1097 +1098 +1099 +1100 +1101 +1102 +1103 +1104 +1105 +1106 +1107 +1108 +1109 +1110 +1111 +1112 +1113 +1114 +1115 +1116 +1117 +1118 +1119 +1120 +1121 +1122 +1123 +1124 +1125 +1126 +1127 +1128 +1129 +1130 +1131 +1132 +1133 +1134 +1135 +1136 +1137 +1138 +1139 +1140 +1141 +1142 +1143 +1144 +1145 +1146 +1147 +1148 +1149 +1150 +1151 +1152 +1153 +1154 +1155 +1156 +1157 +1158 +1159 +1160 +1161 +1162 +1163 +1164 +1165 +1166 +1167 +1168 +1169 +1170 +1171 +1172 +1173 +1174 +1175 +1176 +1177 +1178 +1179 +1180 +1181 +1182 +1183 +1184 +1185 +1186 +1187 +1188 +1189 +1190 +1191 +1192 +1193 +1194 +1195 +1196 +1197 +1198 +1199 +1200 +1201 +1202 +1203 +1204 +1205 +1206 +1207 +1208 +1209 +1210 +1211 +1212 +1213 +1214 +1215 +1216 +1217 +1218 +1219 +1220 +1221 +1222 +1223 +1224 +1225 +1226 +1227 +1228 +1229 +1230 +1231 +1232 +1233 +1234 +1235 +1236 +1237 +1238 +1239 +1240 +1241 +1242 +1243 +1244 +1245 +1246 +1247 +1248 +1249 +1250 +1251 +1252 +1253 +1254 +1255 +1256 +1257 +1258 +1259 +1260 +1261 +1262 +1263 +1264 +1265 +1266 +1267 +1268 +1269 +1270 +1271 +1272 +1273 +1274 +1275 +1276 +1277 +1278 +1279 +1280 +1281 +1282 +1283 +1284 +1285 +1286 +1287 +1288 +1289 +1290 +1291 +1292 +1293 +1294 +1295 +1296 +1297 +1298 +1299 +1300 +1301 +1302 +1303 +1304 +1305 +1306 +1307 +1308 +1309 +1310 +1311 +1312 +1313 +1314 +1315 +1316 +1317 +1318 +1319 +1320 +1321 +1322 +1323 +1324 +1325 +1326 +1327 +1328 +1329 +1330 +1331 +1332 +1333 +1334 +1335 +1336 +1337 +1338 +1339 +1340 +1341 +1342 +1343 +1344 +1345 +1346 +1347 +1348 +1349 +1350 +1351 +1352 +1353 +1354 +1355 +1356 +1357 +1358 +1359 +1360 +1361 +1362 +1363 +1364 +1365 +1366 +1367 +1368 +1369 +1370 +1371 +1372 +1373 +1374 +1375 +1376 +1377 +1378 +1379 +1380 +1381 +1382 +1383 +1384 +1385 +1386 +1387 +1388 +1389 +1390 +1391 +1392 +1393 +1394 +1395 +1396 +1397 +1398 +1399 +1400 +1401 +1402 +1403 +1404 +1405 +1406 +1407 +1408 +1409 +1410 +1411 +1412 +1413 +1414 +1415 +1416 +1417 +1418 +1419 +1420 +1421 +1422 +1423 +1424 +1425 +1426 | 1x +1x +1x + +1x + + + + + + + +1x +1x +1x +1x +1x +1x +1x + +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import * as React from "react";
+import FragmentRender from "./FragmentRender";
+import { CollapseData } from "../../__mocks__/mockStore";
+
+export default {
+ title: "Components/Fragment_Renderer/FragmentRender",
+ component: FragmentRender,
+ locale: "en",
+};
+
+const Template = (args) => <FragmentRender {...args} />;
+
+export const ArticleCTA = Template.bind({});
+export const TextWithImage = Template.bind({});
+export const TextWithImageCollapse = Template.bind({});
+export const QuoteVerticalLineContent = Template.bind({});
+export const TextContent = Template.bind({});
+export const Button = Template.bind({});
+export const ImageWithCollapse = Template.bind({});
+
+ArticleCTA.args = {
+ locale: "en",
+ fragments: [
+ {
+ _model: {
+ title: "SCLabs-Feature-v1",
+ },
+ scId: "INFORMATION-ALPHA-SCLABS",
+ scTitleEn: "Information",
+ scTitleFr: "Information",
+ scContentEn: {
+ json: [
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value: "Alpha:",
+ format: {
+ variants: ["strong"],
+ },
+ },
+ {
+ nodeType: "text",
+ value:
+ " Building a draft tool or service and testing it to see if it meets needs.",
+ },
+ ],
+ },
+ ],
+ },
+ scContentFr: {
+ json: [
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value: "Alpha : ",
+ format: {
+ variants: ["strong"],
+ },
+ },
+ {
+ nodeType: "text",
+ value:
+ "Construire une première version d’un outil ou d’un service et le tester pour savoir s’il répond aux besoins.",
+ },
+ ],
+ },
+ ],
+ },
+ scLabsButton: [
+ {
+ scId: "GIVE-FEEDBACK-OAS-ESTIMATOR",
+ scTitleEn: "Give feedback",
+ scTitleFr: "Fournir des commentaires",
+ scDestinationURLEn:
+ "https://srv217.services.gc.ca/ihst4/Intro.aspx?cid=74938e05-8e91-42a9-8e9d-29daf79f6fe0&lc=eng",
+ scDestinationURLFr:
+ "https://srv217.services.gc.ca/ihst4/Intro.aspx?cid=74938e05-8e91-42a9-8e9d-29daf79f6fe0&lc=fra",
+ scButtonType: ["gc:custom/decd-endc/button-type/secondary"],
+ },
+ ],
+ },
+ ],
+};
+
+TextWithImage.args = {
+ locale: "en",
+ fragments: [
+ {
+ _model: {
+ title: "SCLabs-Comp-Content-Image-v1",
+ },
+ scId: "NAVIGATOR-DIFFICULTIES-MAIN",
+ scLabContent: [
+ {
+ scId: "DIFFICULTIES-COMMUNITY-WORKERS",
+ scContentEn: {
+ json: [
+ {
+ nodeType: "header",
+ style: "h1",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Difficulties faced by community workers who help people with their benefits",
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Government benefits are designed to improve the lives of Canadians. Many benefits help people based on their health, job, housing, or family situation.",
+ },
+ {
+ nodeType: "line-break",
+ content: [],
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "According to the 2022 Auditor General’s report, accessing these benefits can be hard for many reasons (see ",
+ },
+ {
+ nodeType: "link",
+ data: {
+ href: "https://www.oag-bvg.gc.ca/internet/English/parl_oag_202205_01_e_44033.html",
+ },
+ value: "Access to Benefits for Hard-to-Reach Populations",
+ },
+ {
+ nodeType: "text",
+ value: ").",
+ },
+ {
+ nodeType: "line-break",
+ content: [],
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "The report lists a few of those reasons. It also lists some options available to those who need help with applying.",
+ },
+ {
+ nodeType: "line-break",
+ content: [],
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "The report says that people often rely on community organizations to learn about the help they could receive. We saw a similar trend in other research reports. From that, we concluded that community workers play an important role in helping people get government benefits. So, we decided to learn more about the problems that they face when they carry out this task.",
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Here are some problems that we identified from our own research studies and other reports.",
+ },
+ ],
+ },
+ {
+ nodeType: "header",
+ style: "h2",
+ content: [
+ {
+ nodeType: "text",
+ value: "It takes time to learn about government benefits",
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "We talked to several community workers who said it takes a lot of time and effort to become familiar with government benefits. This is because there are so many of them, they come from different sources, and they have different eligibility criteria.",
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "They also said it’s hard to understand information on government websites. This was also mentioned in the reports we read.",
+ },
+ ],
+ },
+ {
+ nodeType: "header",
+ style: "h2",
+ content: [
+ {
+ nodeType: "text",
+ value: "It's hard to stay updated on news about benefits",
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "From our research, we learned that community workers try to stay updated on news about benefits, but don’t have a good way to do so.",
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "There isn’t one location that a person can go to see all the updates. Instead, the workers we talked to said that they made their own solutions. Some created news alerts, others subscribed to newsletters. Despite that, they were sure that they were missing some updates.",
+ },
+ ],
+ },
+ {
+ nodeType: "header",
+ style: "h2",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "It's hard to understand eligibility conditions and the application process",
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "The reports we read said that it’s difficult to apply for benefits because applications are long and ask for a lot of information.",
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "The workers we talked to said that it’s hard to know which forms people need and where to find them.",
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Complicated eligibility criteria make it hard to know if someone qualifies for a benefit. This can stop people from starting a long application process. Most don’t want to spend the effort if they don’t think they qualify.",
+ },
+ ],
+ },
+ {
+ nodeType: "header",
+ style: "h2",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "We want to make it easier to understand government benefits",
+ },
+ {
+ nodeType: "line-break",
+ content: [],
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "To fix the problems identified in our research, we want to make a tool that simplifies information about government benefits.",
+ },
+ {
+ nodeType: "line-break",
+ content: [],
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value: "This tool will make it easier for anyone to:",
+ },
+ {
+ nodeType: "line-break",
+ content: [],
+ },
+ ],
+ },
+ {
+ nodeType: "unordered-list",
+ content: [
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value: "be aware of benefits ",
+ },
+ ],
+ },
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value: "know how to apply ",
+ },
+ ],
+ },
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value: "stay updated on changes ",
+ },
+ ],
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "By making this information easier to understand, we believe more people will apply for the benefits to which they are entitled.",
+ },
+ {
+ nodeType: "line-break",
+ content: [],
+ },
+ ],
+ },
+ ],
+ },
+ scContentFr: {
+ json: [
+ {
+ nodeType: "header",
+ style: "h1",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Difficultés rencontrées par les travailleuses et travailleurs communautaires qui aident les gens avec leurs prestations",
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Les prestations du gouvernement sont conçues pour améliorer la vie des gens. Plusieurs prestations aident les personnes selon leur état de santé, leur emploi, leur logement ou leur situation familiale.",
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Selon le rapport de la vérificatrice générale de 2022, l’accès aux prestations peut être difficile pour de nombreuses raisons (voir ",
+ },
+ {
+ nodeType: "link",
+ data: {
+ href: "https://www.oag-bvg.gc.ca/internet/Francais/parl_oag_202205_01_f_44033.html",
+ },
+ value:
+ "L’accès aux prestations pour les populations difficiles à joindre",
+ },
+ {
+ nodeType: "text",
+ value: ").",
+ },
+ {
+ nodeType: "line-break",
+ content: [],
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Le rapport énumère quelques-unes de ces raisons. Il énumère aussi des options disponibles pour les gens qui ont besoin d’aide pour faire la demande de prestations.",
+ },
+ {
+ nodeType: "line-break",
+ content: [],
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Le rapport explique que les gens ont souvent recours aux organismes communautaires pour en savoir plus sur l'aide qu’ils pourraient recevoir. Nous avons constaté une tendance similaire dans d’autres projets de recherche. Nous en avons conclu que les travailleuses et travailleurs communautaires jouent un rôle important en aidant les gens à obtenir des prestations gouvernementales. Nous avons donc décidé d’en savoir plus sur les obstacles rencontrés lorsqu’ils accomplissent cette tâche.",
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Voici quelques problèmes que nous avons identifiés dans nos recherches et d’autres rapports. ",
+ },
+ ],
+ },
+ {
+ nodeType: "header",
+ style: "h2",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Il faut du temps pour se renseigner sur les prestations",
+ },
+ {
+ nodeType: "line-break",
+ content: [],
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Nous avons parlé à plusieurs travailleuses et travailleurs communautaires qui ont dit qu’il faut beaucoup de temps et d’efforts pour se familiariser avec les prestations gouvernementales. La raison est qu’elles sont très nombreuses, proviennent de sources différentes et ont des critères d’admissibilité différents.",
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Ils nous ont aussi dit qu’il est difficile de comprendre l’information sur les sites Web du gouvernement. C'est également ce qui ressort des rapports que nous avons lus.",
+ },
+ ],
+ },
+ {
+ nodeType: "header",
+ style: "h2",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Il est difficile de se tenir au courant des nouveautés à propos des prestations",
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Nos recherches nous ont appris que les travailleuses et travailleurs communautaires essaient de se tenir au courant des nouvelles concernant les prestations, mais n'ont pas de bon moyen de le faire.",
+ },
+ {
+ nodeType: "line-break",
+ content: [],
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Il n'existe pas d'endroit où l'on peut consulter toutes les mises à jour. Au lieu de cela, les travailleuses et travailleurs auxquels nous avons parlé ont dit qu'ils avaient trouvé leurs propres solutions. Certaines personnes ont créé des alertes, d’autres se sont abonnées à des bulletins d'information. Malgré cela, elles étaient sûres que des mises à jour leur échappaient.",
+ },
+ ],
+ },
+ {
+ nodeType: "header",
+ style: "h2",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Il est difficile de comprendre les conditions d'admissibilité et la procédure de demande",
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Les rapports que nous avons lus indiquent qu'il est difficile de demander des prestations parce que les formulaires sont longs et exigent beaucoup d'informations.",
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Les travailleuses et travailleurs auxquels nous avons parlé ont dit qu'il était difficile de savoir de quels formulaires les gens avaient besoin et où les trouver.",
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "La complexité des critères d'admissibilité fait qu'il est difficile de savoir si une personne a droit à une prestation. Cela peut empêcher les gens d'entamer une longue procédure de demande. La plupart ne veulent pas faire cet effort s'ils pensent qu'ils n'ont pas droit à une prestation. ",
+ },
+ ],
+ },
+ {
+ nodeType: "header",
+ style: "h2",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Nous voulons faciliter la compréhension des prestations gouvernementales ",
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Pour résoudre les problèmes identifiés dans nos recherches, nous voulons créer un outil qui simplifie l'information sur les prestations gouvernementales. ",
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value: "Cet outil permettra de mieux :",
+ },
+ ],
+ },
+ {
+ nodeType: "unordered-list",
+ content: [
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value: "connaître les prestations;",
+ },
+ ],
+ },
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value: "savoir comment présenter une demande;",
+ },
+ ],
+ },
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value: "rester au courant des changements.",
+ },
+ ],
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "En rendant ces informations plus faciles à comprendre, nous pensons que plus de personnes demanderont les prestations auxquelles elles ont droit. ",
+ },
+ {
+ nodeType: "line-break",
+ content: [],
+ },
+ ],
+ },
+ ],
+ },
+ },
+ ],
+ scLabImage: {
+ scId: "COMMUNITY-WORKERS-IMAGE",
+ scImageEn: {
+ _publishUrl:
+ "https://www.canada.ca/content/dam/decd-endc/images/sclabs/benefits-navigator/community-workers.jpg",
+ width: 555,
+ height: 321,
+ },
+ scImageFr: {
+ _publishUrl:
+ "https://www.canada.ca/content/dam/decd-endc/images/sclabs/benefits-navigator/community-workers.jpg",
+ width: 555,
+ height: 321,
+ },
+ scImageMobileEn: null,
+ scImageMobileFr: null,
+ scImageAltTextEn: "Community workers helping people",
+ scImageAltTextFr:
+ "Travailleuses et travailleurs communautaires qui aident des gens",
+ scImageCaptionEn: {
+ json: null,
+ },
+ scImageCaptionFr: {
+ json: null,
+ },
+ },
+ scLabLayout: "default",
+ },
+ ],
+};
+
+TextWithImageCollapse.args = {
+ locale: "en",
+ fragments: [
+ {
+ _model: {
+ title: "SCLabs-Comp-Content-Image-v1",
+ },
+ scId: "NAVIGATOR-DIFFICULTIES-MAIN",
+ scLabContent: [
+ {
+ scId: "FEATURE-DASHBOARD",
+ scContentEn: {
+ json: [
+ {
+ nodeType: "header",
+ style: "h3",
+ content: [
+ {
+ nodeType: "text",
+ value: "Information is clearly presented ",
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value: "On the dashboard, you will find: ",
+ },
+ ],
+ },
+ {
+ nodeType: "unordered-list",
+ content: [
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value: "all your benefits on the same page ",
+ },
+ ],
+ },
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "a menu to access your personal information and security settings",
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ scContentFr: {
+ json: [
+ {
+ nodeType: "header",
+ style: "h3",
+ content: [
+ {
+ nodeType: "text",
+ value: "Information clairement présentée",
+ },
+ {
+ nodeType: "line-break",
+ content: [],
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value: "Sur le tableau de bord, vous trouverez :",
+ },
+ ],
+ },
+ {
+ nodeType: "unordered-list",
+ content: [
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value: "toutes vos prestations sur la même page;",
+ },
+ ],
+ },
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "un menu pour accéder à vos informations personnelles et à vos paramètres de sécurité.",
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ scFragments: [
+ {
+ scId: "FEATURE-DASHBOARD",
+ scImageEn: {
+ _publishUrl:
+ "https://www.canada.ca/content/dam/decd-endc/images/sclabs/client-hub/feature-dashboard-en.png",
+ width: 759,
+ height: 498,
+ },
+ scImageFr: {
+ _publishUrl:
+ "https://www.canada.ca/content/dam/decd-endc/images/sclabs/client-hub/feature-dashboard-fr.png",
+ width: 758,
+ height: 498,
+ },
+ scImageMobileEn: null,
+ scImageMobileFr: null,
+ scImageAltTextEn:
+ "My dashboard page from My Service Canada Account",
+ scImageAltTextFr:
+ "Page Mon tableau de bord de Mon dossier Service Canada",
+ scImageCaptionEn: {
+ json: null,
+ },
+ scImageCaptionFr: {
+ json: null,
+ },
+ scLongDescHeadingEn: "Text version of the image My dashboard",
+ scLongDescHeadingFr:
+ "Version textuelle de l’image Mon tableau de bord",
+ scLongDescEn: {
+ json: [
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value: "The dashboard page includes: ",
+ },
+ ],
+ },
+ {
+ nodeType: "unordered-list",
+ content: [
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value: "a heading with: ",
+ },
+ {
+ nodeType: "unordered-list",
+ content: [
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "the name of the site: My Service Canada Account ",
+ },
+ ],
+ },
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value: "an “Account” menu ",
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value: "benefits, such as: ",
+ },
+ {
+ nodeType: "unordered-list",
+ content: [
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Employment Insurance, with a link to applications, payments and claims, taxes, reports and documents, personal information ",
+ },
+ {
+ nodeType: "line-break",
+ content: [],
+ },
+ ],
+ },
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Canada Pension Plan, with a link to applications, payments, taxes, documents, provisions, personal information ",
+ },
+ {
+ nodeType: "line-break",
+ content: [],
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ scLongDescFr: {
+ json: [
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Le tableau de bord contient les éléments suivants : ",
+ },
+ ],
+ },
+ {
+ nodeType: "unordered-list",
+ content: [
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value: "un en-tête avec : ",
+ },
+ {
+ nodeType: "unordered-list",
+ content: [
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "le nom du site : Mon dossier Service Canada; ",
+ },
+ ],
+ },
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value: "un menu « Compte »; ",
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value: "des prestations, telles que : ",
+ },
+ {
+ nodeType: "unordered-list",
+ content: [
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Assurance-emploi, avec un lien vers les demandes de prestations, paiements et demandes, impôts, rapports et documents, renseignements personnels; ",
+ },
+ ],
+ },
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Régime de pensions du Canada, avec un lien vers les demandes de prestations, paiements, impôts, documents, clauses, renseignements personnels.",
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ },
+ ],
+ },
+ ],
+ scLabImage: {
+ scImageEn: {
+ _publishUrl:
+ "https://www.canada.ca/content/dam/decd-endc/images/sclabs/client-hub/feature-dashboard-en.png",
+ width: 759,
+ height: 498,
+ },
+ scImageFr: {
+ _publishUrl:
+ "https://www.canada.ca/content/dam/decd-endc/images/sclabs/client-hub/feature-dashboard-fr.png",
+ width: 758,
+ height: 498,
+ },
+ scImageMobileEn: null,
+ scImageMobileFr: null,
+ scImageAltTextEn: "My dashboard page from My Service Canada Account",
+ scImageAltTextFr:
+ "Page Mon tableau de bord de Mon dossier Service Canada",
+ scImageCaptionEn: {
+ json: null,
+ },
+ scImageCaptionFr: {
+ json: null,
+ },
+ scLongDescHeadingEn: "Text version of the image My dashboard",
+ scLongDescHeadingFr: "Version textuelle de l’image Mon tableau de bord",
+ scLongDescEn: {
+ json: [
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value: "The dashboard page includes: ",
+ },
+ ],
+ },
+ {
+ nodeType: "unordered-list",
+ content: [
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value: "a heading with: ",
+ },
+ {
+ nodeType: "unordered-list",
+ content: [
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "the name of the site: My Service Canada Account",
+ },
+ ],
+ },
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value: "an “Account” menu",
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value: "benefits, such as: ",
+ },
+ {
+ nodeType: "unordered-list",
+ content: [
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Employment Insurance, with a link to applications, payments and claims, taxes, reports and documents, personal information",
+ },
+ {
+ nodeType: "line-break",
+ content: [],
+ },
+ ],
+ },
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Canada Pension Plan, with a link to applications, payments, taxes, documents, provisions, personal information",
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ scLongDescFr: {
+ json: [
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value: "Le tableau de bord contient les éléments suivants : ",
+ },
+ ],
+ },
+ {
+ nodeType: "unordered-list",
+ content: [
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value: "un en-tête avec : ",
+ },
+ {
+ nodeType: "unordered-list",
+ content: [
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "le nom du site : Mon dossier Service Canada; ",
+ },
+ ],
+ },
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value: "un menu « Compte »; ",
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value: "des prestations, telles que : ",
+ },
+ {
+ nodeType: "unordered-list",
+ content: [
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Assurance-emploi, avec un lien vers les demandes de prestations, paiements et demandes, impôts, rapports et documents, renseignements personnels; ",
+ },
+ ],
+ },
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Régime de pensions du Canada, avec un lien vers les demandes de prestations, paiements, impôts, documents, clauses, renseignements personnels.",
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ },
+ scLabLayout: "image-vertical-line-content",
+ scLongDescHeadingEn: CollapseData.scLongDescHeadingEn,
+ scLongDescHeadingFr: CollapseData.scLongDescHeadingFr,
+ scLongDescEn: CollapseData.scLongDescEn,
+ scLongDescFr: CollapseData.scLongDescFr,
+ },
+ ],
+};
+
+TextContent.args = {
+ locale: "en",
+ fragments: [
+ {
+ _model: {
+ title: "SCLabs-Content-v1",
+ },
+ _path:
+ "/content/dam/decd-endc/content-fragments/sclabs/components/tooltips/information-alpha",
+ scId: "INFORMATION-ALPHA-SCLABS",
+ scTitleEn: "Information",
+ scTitleFr: "Information",
+ scContentEn: {
+ json: [
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value: "Alpha:",
+ format: {
+ variants: ["strong"],
+ },
+ },
+ {
+ nodeType: "text",
+ value:
+ " Building a draft tool or service and testing it to see if it meets needs.",
+ },
+ ],
+ },
+ ],
+ },
+ scContentFr: {
+ json: [
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value: "Alpha : ",
+ format: {
+ variants: ["strong"],
+ },
+ },
+ {
+ nodeType: "text",
+ value:
+ "Construire une première version d’un outil ou d’un service et le tester pour savoir s’il répond aux besoins.",
+ },
+ ],
+ },
+ ],
+ },
+ },
+ ],
+};
+
+ImageWithCollapse.args = {
+ locale: "en",
+ fragments: [
+ {
+ _model: {
+ title: "SCLabs-Image-v1",
+ },
+ scId: "NEWS-IMAGE",
+ scImageEn: {
+ _publishUrl: CollapseData.scImageEn._publishUrl,
+ width: CollapseData.scImageEn.width,
+ height: CollapseData.scImageEn.height,
+ },
+ scImageFr: {
+ _publishUrl:
+ "https://www.canada.ca/content/dam/decd-endc/images/sclabs/benefits-navigator/news-fr.png",
+ width: 1363,
+ height: 890,
+ },
+ scImageMobileEn: null,
+ scImageMobileFr: null,
+ scImageAltTextEn: "Benefit news and updates page",
+ scImageAltTextFr: "Page Nouvelles et mises à jour sur les prestations",
+ scImageCaptionEn: {
+ json: [
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value: "Figure 1",
+ },
+ ],
+ },
+ ],
+ },
+ scImageCaptionFr: {
+ json: [
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value: "Figure 1",
+ },
+ ],
+ },
+ ],
+ },
+ scLongDescHeadingEn: CollapseData.scLongDescHeadingEn,
+ scLongDescHeadingFr: CollapseData.scLongDescHeadingFr,
+ scLongDescEn: CollapseData.scLongDescEn,
+ scLongDescFr: CollapseData.scLongDescFr,
+ },
+ ],
+};
+
+Button.args = {
+ locale: "en",
+ fragments: [
+ {
+ _model: {
+ title: "SCLabs-Button-v1",
+ },
+ scId: "SIGN-IN-MSCA-BUTTON",
+ scTitleEn: "Sign in to My Service Canada Account",
+ scTitleFr: "Se connecter à Mon dossier Service Canada",
+ scDestinationURLEn:
+ "https://www.canada.ca/en/employment-social-development/services/my-account.html",
+ scDestinationURLFr:
+ "https://www.canada.ca/fr/emploi-developpement-social/services/mon-dossier.html",
+ scButtonType: ["gc:custom/decd-endc/button-type/primary"],
+ },
+ ],
+};
+
+QuoteVerticalLineContent.args = {
+ locale: "en",
+ fragments: [
+ {
+ _model: {
+ title: "SCLabs-Comp-Content-v1",
+ },
+ scId: "ESTIMATOR-FUTURE-ESTIMATE-COMMENT-1",
+ scLabContent: [
+ {
+ scContentEn: {
+ json: [
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "I didn’t like having to change my birth year to get an estimate",
+ },
+ ],
+ },
+ ],
+ },
+ scContentFr: {
+ json: [
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Je n’aimais pas devoir changer mon année de naissance pour avoir une estimation",
+ },
+ ],
+ },
+ ],
+ },
+ },
+ {
+ scContentEn: {
+ json: [
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "We now generate results that give future estimates to those who aren’t eligible yet. ",
+ },
+ ],
+ },
+ ],
+ },
+ scContentFr: {
+ json: [
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Nous générons maintenant des résultats qui donnent des estimations futures aux personnes qui ne sont pas encore admissibles. ",
+ },
+ {
+ nodeType: "line-break",
+ content: [],
+ },
+ ],
+ },
+ ],
+ },
+ },
+ ],
+ scLabLayout: "quote",
+ },
+ ],
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import Head from "next/head"; + +export default function PageHead(props) { + return ( + <Head> + {/* Primary HTML Meta Tags */} + <title> + {props.locale === "en" + ? `${props.pageData.scTitleEn} - Service Canada Labs` + : `${props.pageData.scTitleFr} - Laboratoires de Service Canada`} + </title> + <meta + name="description" + content={ + props.locale === "en" + ? props.pageData.scTitleEn + : props.pageData.scTitleFr + } + /> + <meta name="author" content="Service Canada" /> + <link rel="icon" href="/favicon.ico" /> + <link rel="schema.dcterms" href="http://purl.org/dc/terms/" /> + <meta + name="keywords" + content={ + props.locale === "en" + ? props.pageData.scKeywordsEn + : props.pageData.scKeywordsFr + } + /> + + {/* DCMI Meta Tags */} + <meta + name="dcterms.title" + content={ + props.locale === "en" + ? props.pageData.scTitleEn + : props.pageData.scTitleFr + } + /> + <meta + name="dcterms.language" + content={props.locale === "en" ? "eng" : "fra"} + title="ISO639-2/T" + /> + <meta + name="dcterms.creator" + content={ + props.locale === "en" + ? "Employment and Social Development Canada" + : "Emploi et Développement social Canada" + } + /> + <meta name="dcterms.accessRights" content="2" /> + <meta name="dcterms.service" content="ESDC-EDSC_SCLabs-LaboratoireSC" /> + <meta name="dcterms.issued" title="W3CDTF" content="2023-07-07" /> + + <meta name="dcterms.modified" title="W3CDTF" content="2023-07-07" /> + <meta + name="dcterms.description" + content={ + props.locale === "en" + ? props.pageData.scTitleEn + : props.pageData.scTitleFr + } + /> + <meta + name="dcterms.subject" + title="gccore" + content={props.pageData.scSubject} + /> + <meta name="dcterms.spatial" content="Canada" /> + + {/* Open Graph / Facebook */} + <meta property="og:type" content="website" /> + <meta property="og:locale" content={props.locale} /> + <meta + property="og:url" + content={ + "https://alpha.service.canada.ca" + + `${ + props.locale === "en" + ? props.pageData.scPageNameEn + : props.pageData.scPageNameFr + }` + } + /> + <meta + property="og:title" + content={ + props.locale === "en" + ? props.pageData.scTitleEn + : props.pageData.scTitleFr + } + /> + <meta + property="og:description" + content={ + props.locale === "en" + ? props.pageData.scTitleEn + : props.pageData.scTitleFr + } + /> + <meta + property="og:image" + content={props.pageData.scSocialMediaImageEn?._publishUrl} + /> + <meta + property="og:image:alt" + content={ + props.locale === "en" + ? props.pageData.scTitleEn + : props.pageData.scTitleFr + } + /> + + {/* Twitter */} + <meta property="twitter:card" content="summary_large_image" /> + <meta + property="twitter:url" + content={ + "https://alpha.service.canada.ca" + + `${ + props.locale === "en" + ? props.pageData.scPageNameEn + : props.pageData.scPageNameFr + }` + } + /> + <meta + property="twitter:title" + content={ + props.locale === "en" + ? props.pageData.scTitleEn + : props.pageData.scTitleFr + } + /> + <meta name="twitter:creator" content="Service Canada" /> + <meta + property="twitter:description" + content={ + props.locale === "en" + ? props.pageData.scTitleEn + : props.pageData.scTitleFr + } + /> + <meta + property="twitter:image" + content={props.pageData.scSocialMediaImageEn?._publishUrl} + /> + <meta + property="twitter:image:alt" + content={ + props.locale === "en" + ? props.pageData.scTitleEn + : props.pageData.scTitleFr + } + /> + </Head> + ); +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 | 4x + +5x + + + + + + + + + + + | import { CTA } from "../../molecules/CTA"; + +export default function ArticleCTA({ heading, body, ButtonProps, LinkProps }) { + return ( + <CTA + heading={heading} + body={body} + ButtonProps={ButtonProps} + LinkProps={LinkProps} + containerClass="layout-container my-4" + /> + ); +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 | 1x +1x + +1x + + + + + + +1x +1x + + + + + + + + + + + | import * as React from "react";
+import ArticleCTA from "./ArticleCTA";
+
+export default {
+ title: "Components/Fragment_Renderer/Fragment_Components/ArticleCTA",
+ component: ArticleCTA,
+};
+
+const Template = (args) => <ArticleCTA {...args} />;
+
+export const Default = Template.bind({});
+Default.args = {
+ heading: "This is a heading",
+ body: "This is a body",
+ ButtonProps: {
+ text: "Action Button",
+ },
+ LinkProps: {
+ id: "privacy-policy",
+ text: "Review the Privacy Policy",
+ },
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 | 5x +5x + +4x + + + + + + + + + + + + + + + + + + + + + + + | import Image from "next/image"; +import TextRender from "../../text_node_renderer/TextRender"; + +export default function BasicTextWithImage({ src, alt, width, height, data }) { + return ( + <div className="layout-container grid grid-cols-12 gap-x-6 my-12"> + <div className="hidden lg:grid col-start-8 col-span-5 row-start-1 row-span-2"> + <div className="flex justify-center"> + <div className="h-auto"> + <Image + src={src} + alt={alt} + width={width} + height={height} + sizes="50vw" + quality={100} + /> + </div> + </div> + </div> + <div className="col-span-12 lg:col-span-7"> + <TextRender data={data} excludeH1={true} /> + </div> + </div> + ); +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 | 1x +1x + +1x + + + + + + +1x +1x + + + + + + + + + + + + + + + + + + | import * as React from "react";
+import BasicTextWithImage from "./BasicTextWithImage";
+
+export default {
+ title: "Components/Fragment_Renderer/Fragment_Components/BasicTextWithImage",
+ component: BasicTextWithImage,
+};
+
+const Template = (args) => <BasicTextWithImage {...args} />;
+
+export const Default = Template.bind({});
+Default.args = {
+ src: "https://www.canada.ca/content/dam/decd-endc/images/sclabs/benefits-navigator/navigator-overview.jpg",
+ alt: "image alt text",
+ width: 359,
+ height: 260,
+ data: [
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Every week, our product team meets for Feedback Friday to sort through all the new survey responses. We look at the ratings and comments people shared with us about their experience. ",
+ },
+ ],
+ },
+ ],
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 | 4x + +6x + +7x + + + + + + + + + + + + + + + + + + + | import { ActionButton } from "../../atoms/ActionButton"; + +export default function Button({ id, buttonType, href, text }) { + const style = + buttonType === null + ? "primary" + : buttonType === "gc:custom/decd-endc/button-type/primary" + ? "primary" + : buttonType === "gc:custom/decd-endc/button-type/secondary" + ? "secondary" + : "primary"; + return ( + <div className="layout-container grid grid-cols-12 gap-x-6 my-12"> + <ActionButton + id={id} + style={style} + custom="col-span-12" + href={href} + text={text} + /> + </div> + ); +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 | 1x +1x + +1x + + + + + + +1x +1x +1x + + + + + + +1x + + + + + + | import * as React from "react";
+import Button from "./Button";
+
+export default {
+ title: "Components/Fragment_Renderer/Fragment_Components/Button",
+ component: Button,
+};
+
+const Template = (args) => <Button {...args} />;
+
+export const Primary = Template.bind({});
+export const Secondary = Template.bind({});
+Primary.args = {
+ id: "Primary",
+ buttonType: "gc:custom/decd-endc/button-type/primary",
+ href: "/",
+ text: "Primary Button",
+};
+
+Secondary.args = {
+ id: "Secondary",
+ buttonType: "gc:custom/decd-endc/button-type/secondary",
+ href: "/",
+ text: "Secondary Button",
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import Image from "next/image"; + +export default function ImageFragment(props) { + return ( + <div className="layout-container grid grid-cols-12 gap-x-6 my-12"> + <Image + id={props.scId} + src={ + props.locale === "en" + ? props.fragmentData.scImageEn._publishUrl + : props.fragmentData.scImageFr._publishUrl + } + alt={ + props.locale === "en" + ? props.fragmentData.scImageAltTextEn + : props.fragmentData.scImageAltTextFr + } + className="col-span-12 lg:col-span-10" + width={props.fragmentData.scImageEn.width} + height={props.fragmentData.scImageEn.height} + sizes="(max-width: 768px) 100vw, 80vw" + quality={100} + /> + <p className="grid row-start-2 col-span-12 lg:col-span-10 justify-around"> + {props.locale === "en" + ? props.fragmentData.scImageCaptionEn.json[0].content[0].value + : props.fragmentData.scImageCaptionFr.json[0].content[0].value} + </p> + </div> + ); +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 | + + + + + + + + + + + + + + + + + + + + | import * as React from "react"; +import ImageFragment from "./ImageFragment"; + +export default { + title: "Components/Fragment_Renderer/Fragment_Components/ImageFragment", + component: ImageFragment, +}; + +// const Template = (args) => <ImageFragment {...args} />; + +// export const Default = Template.bind({}); + +// Default.args = { +// locale: "en", +// id: "Primary", +// src: "/image1.png", +// alt: "alt text", +// width: 359, +// height: 260 +// }; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 | 5x +5x +5x + +6x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import Image from "next/image"; +import TextRender from "../../text_node_renderer/TextRender"; +import { Collapse } from "../../molecules/Collapse"; + +export default function ImageVerticalLineContent({ + src, + alt, + width, + height, + data, + longDesc, + title, + children, +}) { + return ( + <div className="layout-container"> + <div className="grid grid-cols-12 gap-x-6 mb-9"> + <div className="mb-6 object-fill col-span-12 row-start-1 xl:row-start-1 xl:col-span-8"> + <Image + src={src} + alt={alt} + height={height} + width={width} + sizes="100vw" + quality={100} + /> + </div> + <div className="col-span-12 row-start-3 xl:col-span-4 xl:row-start-1"> + <div className="py-4 pl-4 border-l-4 border-multi-blue-blue60f"> + <TextRender data={data} /> + </div> + </div> + {longDesc ? ( + <div className="mb-6 col-span-12 xl:col-span-8 row-start-2 xl:row-start-2"> + <Collapse data-testid="summary" title={title} children={children} /> + </div> + ) : ( + "" + )} + </div> + </div> + ); +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 | 1x +1x +1x +1x + +1x + + + + + + + + + + + + + + +1x +1x +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import * as React from "react";
+import ImageVerticalLineContent from "./ImageVerticalLineContent";
+import TextRender from "../../text_node_renderer/TextRender";
+import { CollapseData } from "../../../__mocks__/mockStore";
+
+export default {
+ title:
+ "Components/Fragment_Renderer/Fragment_Components/ImageVerticalLineContent",
+ component: ImageVerticalLineContent,
+ decorators: [
+ (Story) => (
+ <div className="layout-container">
+ <Story />
+ </div>
+ ),
+ ],
+};
+
+const Template = (args) => <ImageVerticalLineContent {...args} />;
+
+export const Default = Template.bind({});
+export const WithCollapse = Template.bind({});
+Default.args = {
+ id: "ImageVerticalLineContent",
+ src: CollapseData.scImageEn._publishUrl,
+ alt: "image alt text",
+ width: CollapseData.scImageEn.width,
+ height: CollapseData.scImageEn.height,
+ data: [
+ {
+ nodeType: "header",
+ style: "h3",
+ content: [
+ {
+ nodeType: "text",
+ value: "Information is clearly presented ",
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value: "On the dashboard, you will find: ",
+ },
+ ],
+ },
+ {
+ nodeType: "unordered-list",
+ content: [
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value: "all your benefits on the same page ",
+ },
+ ],
+ },
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "a menu to access your personal information and security settings",
+ },
+ ],
+ },
+ ],
+ },
+ ],
+};
+
+WithCollapse.args = {
+ id: "ImageVerticalLineContent",
+ src: CollapseData.scImageEn._publishUrl,
+ alt: "image alt text",
+ width: 759,
+ height: 497,
+ data: [
+ {
+ nodeType: "header",
+ style: "h3",
+ content: [
+ {
+ nodeType: "text",
+ value: "Information is clearly presented ",
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value: "On the dashboard, you will find: ",
+ },
+ ],
+ },
+ {
+ nodeType: "unordered-list",
+ content: [
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value: "all your benefits on the same page ",
+ },
+ ],
+ },
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "a menu to access your personal information and security settings",
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ title: "Example Title",
+ longDesc: "Test Description",
+ children: <TextRender data={CollapseData.scLongDescEn.json} />,
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 | 4x +4x + +6x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import { Collapse } from "../../molecules/Collapse"; +import Image from "next/image"; + +export default function ImageWithCollapse({ + id, + src, + alt, + width, + height, + content, + longDesc, + title, + children, +}) { + return ( + <div className="layout-container grid grid-cols-12 gap-x-6 my-12"> + <Image + id={id} + src={src} + alt={alt} + className="col-span-12 lg:col-span-10" + width={width} + height={height} + sizes="100vw" + quality={100} + /> + {content ? ( + <p className="grid row-start-2 col-span-12 lg:col-span-10 justify-around mb-8"> + {content} + </p> + ) : ( + "" + )} + {longDesc ? ( + <div className="grid row-start-3 col-span-12 lg:col-span-10"> + <Collapse title={title} children={children} /> + </div> + ) : ( + "" + )} + </div> + ); +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 | 1x +1x +1x +1x + +1x + + + + + + +2x +1x + + + + + + + + + + + | import * as React from "react";
+import ImageWithCollapse from "./ImageWithCollapse";
+import TextRender from "../../text_node_renderer/TextRender";
+import { CollapseData } from "../../../__mocks__/mockStore";
+
+export default {
+ title: "Components/Fragment_Renderer/Fragment_Components/ImageWithCollapse",
+ component: ImageWithCollapse,
+};
+
+const Template = (args) => <ImageWithCollapse {...args} />;
+
+export const Default = Template.bind({});
+Default.args = {
+ id: "ImageWithCollapse",
+ src: CollapseData.scImageEn._publishUrl,
+ alt: "image alt text",
+ width: CollapseData.scImageEn.width,
+ height: CollapseData.scImageEn.height,
+ content: CollapseData.scImageCaptionEn.json[0].content[0].value,
+ title: "Example Title",
+ longDesc: "Test Description",
+ children: <TextRender data={CollapseData.scLongDescEn.json} />,
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 | 4x + +5x + + + + + + + + + + + + + + + + + + + + + | import TextRender from "../../text_node_renderer/TextRender"; + +export default function QuoteVerticalLineContent({ + quoteText, + explanationtext, +}) { + return ( + <div className="layout-container grid grid-cols-12 gap-x-4 my-12"> + <div className="col-span-12 xl:col-span-3"> + <div className="speech-bubble"> + <div className="speech-bubble-top"> + <blockquote className="speech-bubble-quote"> + <TextRender data={quoteText} /> + </blockquote> + </div> + </div> + </div> + <div className="col-span-12 lg:col-span-7 xl:col-span-4 xxl:-ml-14 h-fit p-5 border-l-4 border-multi-blue-blue60f"> + <TextRender data={explanationtext} /> + </div> + </div> + ); +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 | 1x +1x + +1x + + + + + + + +1x +1x + + + + + + + + + + + + + + + + + + + + + + + + + | import * as React from "react";
+import QuoteVerticalLineContent from "./QuoteVerticalLineContent";
+
+export default {
+ title:
+ "Components/Fragment_Renderer/Fragment_Components/QuoteVerticalLineContent",
+ component: QuoteVerticalLineContent,
+};
+
+const Template = (args) => <QuoteVerticalLineContent {...args} />;
+
+export const Default = Template.bind({});
+Default.args = {
+ locale: "en",
+ quoteText: [
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value: "Quote Text",
+ },
+ ],
+ },
+ ],
+ explanationtext: [
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value: "Explanation Text",
+ },
+ ],
+ },
+ ],
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 | 4x + +5x + + + + + + + + + | import TextRender from "../../text_node_renderer/TextRender"; + +export default function TextContent({ data }) { + return ( + <div className="layout-container grid grid-cols-12 gap-x-6 my-12"> + <div className="col-span-12 lg:col-span-7"> + <TextRender data={data} excludeH1={true} /> + </div> + </div> + ); +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 | 1x +1x + +1x + + + + + + +1x + +1x + + + + + + + + + + + + + + | import * as React from "react";
+import TextContent from "./TextContent";
+
+export default {
+ title: "Components/Fragment_Renderer/Fragment_Components/TextContent",
+ component: TextContent,
+};
+
+const Template = (args) => <TextContent {...args} />;
+
+export const Default = Template.bind({});
+
+Default.args = {
+ data: [
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Every week, our product team meets for Feedback Friday to sort through all the new survey responses. We look at the ratings and comments people shared with us about their experience. ",
+ },
+ ],
+ },
+ ],
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 | 4x +4x + +7x + + + + + + + + + + +5x + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import BasicTextWithImage from "./BasicTextWithImage"; +import ImageVerticalLineContent from "./ImageVerticalLineContent"; + +export default function TextWithImage({ + src, + alt, + width, + height, + data, + layout, + title, + longDesc, + children, +}) { + switch (layout) { + case "default": + return ( + <BasicTextWithImage + src={src} + alt={alt} + width={width} + height={height} + data={data} + /> + ); + case "image-vertical-line-content": + return ( + <ImageVerticalLineContent + src={src} + alt={alt} + width={width} + height={height} + data={data} + title={title} + longDesc={longDesc} + children={children} + /> + ); + default: + break; + } +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 | 1x +1x +1x +1x + +1x + + + + + + +1x +1x +1x + +1x + + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import * as React from "react";
+import TextWithImage from "./TextWithImage";
+import TextRender from "../../text_node_renderer/TextRender";
+import { CollapseData } from "../../../__mocks__/mockStore";
+
+export default {
+ title: "Components/Fragment_Renderer/Fragment_Components/TextWithImage",
+ component: TextWithImage,
+};
+
+const Template = (args) => <TextWithImage {...args} />;
+
+export const Default = Template.bind({});
+export const Vertical = Template.bind({});
+export const VerticalWithCollapse = Template.bind({});
+
+Default.args = {
+ src: "/image2.png",
+ alt: "image alt text",
+ width: 759,
+ height: 498,
+ layout: "default",
+ data: [
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "Every week, our product team meets for Feedback Friday to sort through all the new survey responses. We look at the ratings and comments people shared with us about their experience. ",
+ },
+ ],
+ },
+ ],
+};
+
+Vertical.args = {
+ src: CollapseData.scImageEn._publishUrl,
+ alt: "image alt text",
+ width: CollapseData.scImageEn.width,
+ height: CollapseData.scImageEn.height,
+ layout: "image-vertical-line-content",
+ data: [
+ {
+ nodeType: "header",
+ style: "h3",
+ content: [
+ {
+ nodeType: "text",
+ value: "Information is clearly presented ",
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value: "On the dashboard, you will find: ",
+ },
+ ],
+ },
+ {
+ nodeType: "unordered-list",
+ content: [
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value: "all your benefits on the same page ",
+ },
+ ],
+ },
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "a menu to access your personal information and security settings",
+ },
+ ],
+ },
+ ],
+ },
+ ],
+};
+
+VerticalWithCollapse.args = {
+ src: CollapseData.scImageEn._publishUrl,
+ alt: "image alt text",
+ width: CollapseData.scImageEn.width,
+ height: CollapseData.scImageEn.height,
+ layout: "image-vertical-line-content",
+ data: [
+ {
+ nodeType: "header",
+ style: "h3",
+ content: [
+ {
+ nodeType: "text",
+ value: "Information is clearly presented ",
+ },
+ ],
+ },
+ {
+ nodeType: "paragraph",
+ content: [
+ {
+ nodeType: "text",
+ value: "On the dashboard, you will find: ",
+ },
+ ],
+ },
+ {
+ nodeType: "unordered-list",
+ content: [
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value: "all your benefits on the same page ",
+ },
+ ],
+ },
+ {
+ nodeType: "list-item",
+ content: [
+ {
+ nodeType: "text",
+ value:
+ "a menu to access your personal information and security settings",
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ title: "Example Title",
+ longDesc: "Test Description",
+ children: <TextRender data={CollapseData.scLongDescEn.json} />,
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +File | ++ | Statements | ++ | Branches | ++ | Functions | ++ | Lines | ++ |
---|---|---|---|---|---|---|---|---|---|
ArticleCTA.js | +
+
+ |
+ 100% | +2/2 | +100% | +0/0 | +100% | +1/1 | +100% | +2/2 | +
ArticleCTA.stories.js | +
+
+ |
+ 85.71% | +6/7 | +100% | +0/0 | +100% | +0/0 | +100% | +5/5 | +
BasicTextWithImage.js | +
+
+ |
+ 100% | +3/3 | +100% | +0/0 | +100% | +1/1 | +100% | +3/3 | +
BasicTextWithImage.stories.js | +
+
+ |
+ 85.71% | +6/7 | +100% | +0/0 | +100% | +0/0 | +100% | +5/5 | +
Button.js | +
+
+ |
+ 100% | +3/3 | +66.66% | +4/6 | +100% | +1/1 | +100% | +3/3 | +
Button.stories.js | +
+
+ |
+ 90% | +9/10 | +100% | +0/0 | +100% | +0/0 | +100% | +7/7 | +
ImageFragment.js | +
+
+ |
+ 0% | +0/2 | +0% | +0/6 | +0% | +0/1 | +0% | +0/2 | +
ImageFragment.stories.js | +
+
+ |
+ 0% | +0/4 | +100% | +0/0 | +100% | +0/0 | +0% | +0/3 | +
ImageVerticalLineContent.js | +
+
+ |
+ 100% | +4/4 | +100% | +2/2 | +100% | +1/1 | +100% | +4/4 | +
ImageVerticalLineContent.stories.js | +
+
+ |
+ 91.66% | +11/12 | +100% | +0/0 | +100% | +0/0 | +100% | +9/9 | +
ImageWithCollapse.js | +
+
+ |
+ 100% | +3/3 | +50% | +2/4 | +100% | +1/1 | +100% | +3/3 | +
ImageWithCollapse.stories.js | +
+
+ |
+ 88.88% | +8/9 | +100% | +0/0 | +100% | +0/0 | +100% | +7/7 | +
QuoteVerticalLineContent.js | +
+
+ |
+ 100% | +2/2 | +100% | +0/0 | +100% | +1/1 | +100% | +2/2 | +
QuoteVerticalLineContent.stories.js | +
+
+ |
+ 85.71% | +6/7 | +100% | +0/0 | +100% | +0/0 | +100% | +5/5 | +
TextContent.js | +
+
+ |
+ 100% | +2/2 | +100% | +0/0 | +100% | +1/1 | +100% | +2/2 | +
TextContent.stories.js | +
+
+ |
+ 85.71% | +6/7 | +100% | +0/0 | +100% | +0/0 | +100% | +5/5 | +
TextWithImage.js | +
+
+ |
+ 80% | +4/5 | +0% | +0/1 | +100% | +1/1 | +80% | +4/5 | +
TextWithImage.stories.js | +
+
+ |
+ 93.33% | +14/15 | +100% | +0/0 | +100% | +0/0 | +100% | +11/11 | +
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +File | ++ | Statements | ++ | Branches | ++ | Functions | ++ | Lines | ++ |
---|---|---|---|---|---|---|---|---|---|
FragmentRender.js | +
+
+ |
+ 89.28% | +25/28 | +58.73% | +37/63 | +100% | +3/3 | +89.28% | +25/28 | +
FragmentRender.stories.js | +
+
+ |
+ 96.15% | +25/26 | +100% | +0/0 | +100% | +0/0 | +100% | +18/18 | +
PageHead.js | +
+
+ |
+ 0% | +0/2 | +0% | +0/30 | +0% | +0/1 | +0% | +0/2 | +
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +File | ++ | Statements | ++ | Branches | ++ | Functions | ++ | Lines | ++ |
---|---|---|---|---|---|---|---|---|---|
index.js | +
+
+ |
+ 0% | +0/1 | +100% | +0/0 | +100% | +0/0 | +0% | +0/1 | +
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 | + | import "prop-types";
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 | 5x +5x +5x + +7x + + + + + + + +5x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import { DSButton } from "../atoms/DSButton";
+import { Link } from "../atoms/Link";
+import { Image } from "../atoms/Image";
+
+export function CTA({
+ heading,
+ body,
+ ButtonProps,
+ LinkProps,
+ containerClass = "",
+}) {
+ // Check if body prop is HTML content
+ const isHTML = (str) => /<\/?[a-z][\s\S]*>/i.test(str);
+
+ return (
+ <div className="bg-multi-blue-blue2 p-3">
+ <div className={`flex flex-row ${containerClass}`}>
+ <div className="flex flex-col w-[60px] shrink-0">
+ <Image alt="icon" src="/comment_bubble.svg" className="w-[60px]" />
+ <div className="flex-grow divide-x-2 divide-multi-blue-blue60a flex flex-row justify-center mt-3">
+ <div></div>
+ <div></div>
+ </div>
+ </div>
+ <div className="pt-0 pl-5">
+ <h3 className={`leading-[40px] text-multi-neutrals-grey100`}>
+ {heading}
+ </h3>
+ {isHTML(body) ? body : <p className="body">{body}</p>}
+ <DSButton
+ styling="primary"
+ className="my-3"
+ type="button"
+ {...ButtonProps}
+ />
+ {LinkProps && <Link {...LinkProps} />}
+ </div>
+ </div>
+ </div>
+ );
+}
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 | 1x +1x +1x + + + + + + +4x +1x + + + + + + + + + + + +2x +1x + + + + + + + | import * as React from "react";
+import { CTA } from "./CTA";
+export default {
+ title: "Components/Molecules/CTA",
+ component: CTA,
+};
+
+const Template = (args) => <CTA {...args} />;
+
+export const Default = Template.bind({});
+Default.args = {
+ heading: "This is a call-to-action!",
+ body: "This sentence explains the action we want the users to take.",
+ ButtonProps: {
+ text: "Action Button",
+ },
+ LinkProps: {
+ id: "privacy-policy",
+ text: "Review the Privacy Policy",
+ },
+};
+
+export const WithoutLink = Template.bind({});
+WithoutLink.args = {
+ heading: "This is a call-to-action!",
+ body: "This sentence explains the action we want the users to take.",
+ ButtonProps: {
+ text: "Action Button",
+ },
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 | 8x +8x +8x +8x +8x + + + + + +8x +12x + + + + + + +12x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +8x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +13x + | import React from "react"; +import PropTypes from "prop-types"; +import Link from "next/link"; +import { ActionButton } from "../atoms/ActionButton"; +import Image from "next/image"; + +/** + * Displays an experiment card on the page + */ + +export const Card = (props) => { + const tagColours = { + current_projects: "custom-green", + past_projects: "custom-gray", + upcoming_projects: "custom-blue", + new_update: "new-update", + }; + + const tagColour = tagColours[props.tag] ?? "custom-gray"; + + return ( + <Link href={props.href}> + <div + className={`h-full group card-shadow border border-custom-gray-border rounded-md pb-4 hover:cursor-pointer ${ + "border-" + tagColour + }`} + data-testid={props.dataTestId} + data-cy={props.dataCy} + > + {props.showImage ? ( + <div className="sm:h-80 flex justify-center"> + <Image + src={props.imgSrc} + alt={props.imgAlt} + className="object-contain" + width={props.imgWidth} + height={props.imgHeight} + // Cards are single column up to 768px + sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw" + quality={100} + /> + </div> + ) : ( + "" + )} + <div className="flex"> + <p className="block font-display text-lg text-custom-blue-projects-link font-bold underline underline-offset-[6px] my-1 py-2 px-6 items-center group-hover:text-custom-blue-projects-link-hover"> + {props.title} + {props.showIcon ? ( + props.href.substring(0, 8) === "https://" ? ( + <div className="h-4 w-4 ml-1 mt-1 relative"> + <img src={props.icon} alt={props.iconAlt} /> + </div> + ) : ( + "" + ) + ) : ( + "" + )} + </p> + {props.showTag ? ( + <span + className={`block w-max py-2 px-2 font-body font-bold border-l-4 mr-6 mt-auto mb-auto border-${tagColour}-darker bg-${tagColour}-lighter + `} + > + {props.tagLabel} + </span> + ) : ( + "" + )} + </div> + {props.showDate ? ( + <p className="ml-6 text-base text-custom-gray-date"> + {"Posted: " + props.datePosted.substring(0, 10)} + </p> + ) : ( + "" + )} + <p className="text-custom-gray-text mx-6 leading-30px text-lg"> + {props.description} + </p> + {props.showButton ? ( + <ActionButton + href={props.btnHref} + text={props.btnText} + id={props.btnId} + dataCy={props.btnId} + className="flex mt-6 mb-2 ml-4 rounded xxs:w-full xs:w-fit py-2 bg-[#EAEBED] text-custom-blue-text focus:ring-inset focus:ring-2 focus:ring-black hover:bg-details-button-hover-gray text-center border border-details-button-gray" + /> + ) : ( + "" + )} + </div> + </Link> + ); +}; + +Card.propTypes = { + /** + * Title of the experiment card. + */ + title: PropTypes.string.isRequired, + + /** + * tag of the experiment card + */ + tag: PropTypes.string, + + /** + * Link of the card + */ + href: PropTypes.string, + + /** + * the label of the tag card + */ + tagLabel: PropTypes.string, + + /** + * Description of the experiment card. + */ + description: PropTypes.string.isRequired, + + /** + * the test id for unit tests + */ + dataTestId: PropTypes.string, + + /** + * the test id for cypress test + */ + dataCy: PropTypes.string, + + /** + * Boolean value to show or hide image + */ + showImage: PropTypes.bool, + + /** + * Boolean value to show or hide button + */ + showButton: PropTypes.bool, + + /** + * Boolean value to show or hide date + */ + showDate: PropTypes.bool, + + /** + * Boolean value to show or hide icon beside title + */ + showIcon: PropTypes.bool, + + /** + * Boolean value to show or hide tag + */ + showTag: PropTypes.bool, +}; + +export default Card; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 | 1x +1x +1x + +1x + + + + + + +4x +2x +1x +1x +1x + +1x + + + + + + + +1x + + + + + + + + +1x + + + + + + + + +1x + + + + + + + +1x + + + + + + + + | import React from "react"; +import Card from "./Card"; +import Image from "../../public/placeholder.png"; + +export default { + title: "Components/Molecules/Card", + component: Card, +}; + +const Template = (args) => <Card {...args} />; + +export const Primary = Template.bind({}); +export const WithTag = Template.bind({}); +export const WithImage = Template.bind({}); +export const WithDate = Template.bind({}); +export const WithButton = Template.bind({}); + +Primary.args = { + title: "Title", + href: "/some/link", + description: "Description", + imgSrc: "/placeholderImg", + imgAlt: "placeholderAlt", +}; + +WithTag.args = { + showTag: true, + title: "Title", + tag: "experiment_tag", + tagLabel: "Experiment tag", + description: "Description", + href: "/some/link", +}; + +WithImage.args = { + showImage: true, + title: "Title", + description: "Description", + href: "/somelink", + imgSrc: Image, + imgAlt: "placeholderAlt", +}; + +WithDate.args = { + showDate: true, + title: "Title", + href: "/somelink", + datePosted: "2022-01-01", + description: "Description", +}; + +WithButton.args = { + showButton: true, + title: "Title", + description: "Description", + href: "/somelink", + btnHref: "/somelink", + btnText: "Button text", +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 | 8x + +12x +11x +11x + + + + + + + + + + + + + + + + + + + + +8x + + + + + + + + + + + + + + + + + + + + + + + + + | import PropTypes from "prop-types"; + +export function Collapse({ id = "defaultAccordion", ...props }) { + const { title, children } = props; + return ( + <details + key={id} + id={id} + className="mb-[5px] text-multi-neutrals-grey100 leading-[33px] text-mobileh5 font-body" + data-testid="details" + > + <summary + key={`summary-${id}`} + data-testid="summary" + className="text-multi-blue-blue60d hover:hover:text-multi-blue-blue50b hover:underline border border-multi-neutrals-grey40 rounded px-[15px] py-[5px] cursor-pointer select-none outline-none" + > + {title} + </summary> + <div className="border border-multi-neutrals-grey40 rounded-b px-[18px] py-[5px] cursor-pointer select-none outline-none"> + {children} + </div> + </details> + ); +} + +Collapse.propTypes = { + /** + * component id + */ + id: PropTypes.string, + + /** + * Title of the collapsible header + */ + title: PropTypes.string, + + /** + * code passed in to fill the expanded area. + */ + children: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.element, + PropTypes.arrayOf(PropTypes.element), + ]), + + /** + * Test id for unit test + */ + dataTestId: PropTypes.string, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 | 1x +1x + +1x + + + + + + +2x +1x + + + + + + +2x +1x + + + + + + + + + + + + + + + + + | import React from "react";
+import { Collapse } from "./Collapse";
+
+export default {
+ title: "Components/Molecules/Collapse",
+ component: Collapse,
+};
+
+const Template = (args) => <Collapse {...args} />;
+
+export const TextDescription = Template.bind({});
+TextDescription.args = {
+ id: "collapseId",
+ title: "Example title",
+ children: "Example description",
+ dataTestId: "/placeholderImg",
+};
+
+export const HtmlDescription = Template.bind({});
+HtmlDescription.args = {
+ id: "collapseId",
+ title: "Example title",
+ children: [
+ <p>First paragraph tag</p>,
+ <p>Second paragprahp tag</p>,
+ <ul>
+ <li>Unorderded list item 1</li>
+ <li>Unorderded list item 2</li>
+ </ul>,
+ <ol>
+ <li>Ordered list item 1</li>
+ <li>Ordered list item 2</li>
+ </ol>,
+ ],
+ dataTestId: "exampleTestId",
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 | 3x + +9x +9x +9x +9x +9x + + + + + + + + + + +9x + + +7x + + + + + + + + +7x + + + + + + + +7x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +3x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import PropTypes from "prop-types"; + +export function ContextualAlert(props) { + const warning_img = "/warning_img.svg"; + const danger_img = "/danger_img.svg"; + const info_img = "/info_img.svg"; + const success_img = "/success_img.svg"; + + const { + message_heading, + message_body, + id, + type, + alert_icon_id, + alert_icon_alt_text, + asHtml, + whiteBG, + } = props; + + const alert_type = + type === "warning" + ? warning_img + : type === "danger" + ? danger_img + : type === "info" + ? info_img + : success_img; + + const alert_color = + type === "warning" + ? "border-specific-orange-orange50" + : type === "danger" + ? "border-specific-red-red50b" + : type === "info" + ? "border-specific-cyan-cyan50" + : "border-specific-green-green50a"; + + let white_BG = whiteBG ? "bg-multi-neutrals-white" : " "; + + return ( + <div + id={id} + className={`relative min-w-[290px] sm:pl-[24px] pl-[16px] ${white_BG}`} + > + <div className="absolute top-3 sm:left-3.5 left-1.5 bg-multi-neutrals-white py-4px"> + {/* change back to image component once fixed */} + <img id={alert_icon_id} src={alert_type} alt={alert_icon_alt_text} /> + </div> + <div + className={`overflow-auto border-l-6 ${alert_color} pl-[24px] py-[17px] leading-8`} + > + {asHtml ? ( + <h2 + className="mt-0 text-h3 leading-heading3 ml-1" + dangerouslySetInnerHTML={{ __html: message_heading }} + /> + ) : ( + <h2 className="mt-0 text-h3 leading-heading3 ml-1"> + {message_heading} + </h2> + )} + {asHtml ? ( + <div + className="font-body ml-0.5 text-lg" + dangerouslySetInnerHTML={{ __html: message_body }} + /> + ) : ( + <div className="font-body ml-0.5 text-lg">{message_body}</div> + )} + </div> + </div> + ); +} + +ContextualAlert.propTypes = { + /** + * component id + */ + id: PropTypes.string.isRequired, + + /** + * alert type + */ + type: PropTypes.oneOf(["warning", "info", "success", "danger"]).isRequired, + + /** + * id for the alert icon + */ + alert_icon_id: PropTypes.string.isRequired, + + /** + * Alternate text for the alert icon + */ + alert_icon_alt_text: PropTypes.string.isRequired, + + /** + * heading text + */ + message_heading: PropTypes.string.isRequired, + + /** + * body text + */ + message_body: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.element, + PropTypes.arrayOf(PropTypes.element), + ]).isRequired, + + /** + * HTML toggle. Determines if text is parsed as plain text or HTML. + */ + asHtml: PropTypes.bool, + + /** + * If true the background will be white, default is transparent. + */ + whiteBG: PropTypes.bool, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 | 1x +1x + + + + + + +4x +2x +2x +2x + +1x + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + +1x + + + + + + + + + +1x + + + + + + + + + + + + + + + + + + | import { ContextualAlert } from "./ContextualAlert";
+export default {
+ title: "Components/Molecules/ContextualAlert",
+ component: ContextualAlert,
+};
+
+const Template = (args) => <ContextualAlert {...args} />;
+
+export const Success = Template.bind({});
+export const Info = Template.bind({});
+export const Warning = Template.bind({});
+export const Danger = Template.bind({});
+
+Success.args = {
+ id: "success",
+ type: "success",
+ message_heading: "COVID-19 New services and service changes",
+ message_body: [
+ <p>
+ Find out about new support for Canadians during the COVID-19 pandemic and
+ how Service Canada’s services are affectedFind out about new support for
+ Canadians during the COVID-19 pandemic and how Service Canada’s services
+ are affected
+ <a href="https://healthycanadians.gc.ca/video/suspect-eng.php#trans">
+ Transcript
+ </a>
+ </p>,
+ ],
+ alert_icon_alt_text: "success icon",
+ alert_icon_id: "success icon",
+};
+
+Info.args = {
+ id: "info",
+ type: "info",
+ message_heading: "COVID-19 New services and service changes",
+ message_body:
+ "Find out about new support for Canadians during the COVID-19 pandemic and how Service Canada’s services are affectedFind out about new support for Canadians during the COVID-19 pandemic and how Service Canada’s services are affected",
+ alert_icon_alt_text: "info icon",
+ alert_icon_id: "info icon",
+};
+
+Warning.args = {
+ id: "warning",
+ type: "warning",
+ message_heading: "COVID-19 New services and service changes",
+ message_body:
+ "Find out about new support for Canadians during the COVID-19 pandemic and how Service Canada’s services are affectedFind out about new support for Canadians during the COVID-19 pandemic and how Service Canada’s services are affected",
+ alert_icon_alt_text: "warning",
+ alert_icon_id: "warning icon",
+};
+
+Danger.args = {
+ id: "danger",
+ type: "danger",
+ message_heading: "COVID-19 New services and service changes",
+ message_body: [
+ <p>
+ Find out about new support for Canadians during the COVID-19 pandemic and
+ how Service Canada’s services are affectedFind out about new support for
+ Canadians during the COVID-19 pandemic and how Service Canada’s services
+ are affected
+ <a href="https://healthycanadians.gc.ca/video/suspect-eng.php#trans">
+ Transcript
+ </a>
+ </p>,
+ ],
+ alert_icon_alt_text: "danger icon",
+ alert_icon_id: "danger icon",
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 | 2x +2x +2x + +5x +4x + + + + + + + + + + + + + +1x + + + + + + + + + + + + + + + + + + +2x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import PropTypes from "prop-types";
+import Clipboard from "react-copy-to-clipboard";
+import { ActionButton } from "../atoms/ActionButton";
+
+export function CopyToClipboard({ value = "", type = "text", ...props }) {
+ const ifControlledProps = !props.uncontrolled
+ ? {
+ value: value,
+ }
+ : {};
+ return (
+ <div>
+ <input
+ className={`font-body w-full min-h-40px py-6px px-12px text-center ${props.textFieldStyle}`}
+ id={props.id}
+ aria-describedby={props.describedby}
+ name={props.name}
+ placeholder={props.placeholder}
+ type={type}
+ onChange={(e) => props.onChange(e.currentTarget.value)}
+ {...ifControlledProps}
+ data-testid={props.dataTestId}
+ data-cy={props.dataCy}
+ aria-label={props.aria_label}
+ />
+ <Clipboard text={value}>
+ <ActionButton
+ id={props.buttonId}
+ className={`w-full ${props.buttonStyle}`}
+ onClick={props.onClick}
+ >
+ {props.buttonText}
+ </ActionButton>
+ </Clipboard>
+ </div>
+ );
+}
+
+CopyToClipboard.propTypes = {
+ /**
+ * additional css for the component
+ */
+ className: PropTypes.string,
+
+ /**
+ * the id of the text field
+ */
+ id: PropTypes.string.isRequired,
+
+ /**
+ * the name of the text field
+ */
+ name: PropTypes.string.isRequired,
+
+ /**
+ * value of the text field
+ */
+ value: PropTypes.string,
+
+ /**
+ * placeholder for the text field,
+ */
+ placeholder: PropTypes.string,
+
+ /**
+ * the type of the input
+ */
+ type: PropTypes.string,
+
+ /**
+ * call back for when the value of the text field changes
+ */
+ onChange: PropTypes.func,
+
+ /**
+ * call back for when the link has been copied
+ */
+ onClick: PropTypes.func,
+
+ /**
+ * message to display if there is an error
+ */
+ error: PropTypes.string,
+
+ /**
+ * if label should be bold
+ */
+ boldLabel: PropTypes.bool,
+
+ /**
+ * boolean flag to specify that this input should be uncontrolled by react
+ */
+ uncontrolled: PropTypes.bool,
+
+ /**
+ * unit test selector
+ */
+ dataTestId: PropTypes.string,
+
+ /**
+ * cypress tests selector
+ */
+ dataCy: PropTypes.string,
+
+ /**
+ * aria-describedby label id
+ */
+ describedby: PropTypes.string,
+
+ /**
+ * aria-label
+ */
+ aria_label: PropTypes.string,
+
+ /**
+ * Text for ActionButton
+ */
+ buttonText: PropTypes.string,
+ /**
+ * id for ActionButton
+ */
+ buttonId: PropTypes.string,
+ /**
+ * Custom styling for the button
+ */
+ buttonStyle: PropTypes.string,
+ /**
+ * Custom styling for the text field
+ */
+ textFieldStyle: PropTypes.string,
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 | 1x +1x + +1x + + + + + + +5x + +1x + + + + + + + + + + | import React from "react";
+import { CopyToClipboard } from "./CopyToClipboard";
+
+export default {
+ title: "Components/Molecules/CopyToClipboard",
+ component: CopyToClipboard,
+};
+
+const Template = (args) => <CopyToClipboard {...args} />;
+
+export const Primary = Template.bind({});
+
+Primary.args = {
+ buttonId: "clipboardButton",
+ buttonText: "Copy link",
+ buttonStyle: "ieButton",
+ id: "clipboard",
+ name: "theClipboard",
+ textFieldStyle: "ieTextField",
+ dataTestId: "clipboard-controlled",
+ aria_label: "clipboard",
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 | 2x + + + + +11x + + + + + + + + + + + + +2x + + + + + + + + + + + + + + + + + + + + + + + + + + | import PropTypes from "prop-types"; + +/** + * Drop Down Element + */ +export function Details(props) { + return ( + <details data-testid={props.dataTestId} data-cy={props.dataCy}> + <summary className="max-w-450px w-full bg-details-button-gray focus:ring-inset focus:ring-2 focus:ring-black active:bg-details-button-active-gray hover:bg-details-button-hover-gray rounded py-12px px-5px font-body text-sm text-center text-canada-footer-font cursor-pointer border border-outset border-details-button-gray"> + {props.label} + </summary> + <div className="max-w-450px w-full min-h-200px bg-gray-light-200 mt-1 p-15px border border-details-border-gray rounded ring-inset ring-1 ring-gray-light-200"> + {props.children} + </div> + </details> + ); +} + +Details.propTypes = { + /** + * id for the details element + */ + id: PropTypes.string, + + /** + * the label of the details button + */ + label: PropTypes.string.isRequired, + + /** + * the content for the details element + */ + children: PropTypes.node, + + /** + * unit test selector + */ + dataTestId: PropTypes.string, + + /** + * cypress selector + */ + dataCy: PropTypes.string, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 | 1x +1x + +1x + + + + + + +6x +1x + + + + + + | import React from "react";
+import { Details } from "./Details";
+
+export default {
+ title: "Components/Molecules/Details",
+ component: Details,
+};
+
+const Template = (args) => <Details {...args} />;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ id: "unopenedDetails",
+ label: "A Drop Down",
+ children: "Content",
+ dataTestId: "details",
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 | 1x +1x + + + + +4x + + + + + + + + + + + + + + + + +9x + + + + +1x + + + + + + + + + + + + + +1x + + + + + + + + + + + + + + + + + + + + + + + | import PropTypes from "prop-types";
+import { ActionButton } from "../atoms/ActionButton";
+
+/**
+ * error box to be used to summarise error in forms
+ */
+export function ErrorBox({ errors = [], ...props }) {
+ return (
+ <div
+ id="error-box"
+ className="relative border-l-4 border-error-border-red min-h-40px my-10"
+ data-cy="error-box"
+ role="alert"
+ aria-atomic="true"
+ >
+ <span className="icon-error absolute top-1 -left-2.5 bg-white" />
+ <p className="font-bold ml-4 text-p mb-2 lg:text-h4">{props.text}</p>
+ <ul
+ className="w-full list-disc list-outside leading-loose pl-8 text-sm lg:text-p"
+ data-cy="error-box-items"
+ id="error-box-items"
+ >
+ {errors.map(({ id, text }) => {
+ return (
+ <li key={`${id}-${text}`} className="mb-2">
+ <ActionButton
+ id={`${id}-${text}`}
+ custom="font-body hover:text-canada-footer-hover-font-blue text-canada-footer-font underline inline-block text-left"
+ onClick={() => props.onClick(id)}
+ dataCy={`error-item-${id}`}
+ className="" // This is to avoid all the "undefined" class names applied.
+ >
+ {text}
+ </ActionButton>
+ </li>
+ );
+ })}
+ </ul>
+ </div>
+ );
+}
+
+ErrorBox.propTypes = {
+ /**
+ * An array of error messages to display. Each object contains the id of the element which
+ * when the text is clicked the browser will scroll too
+ */
+ text: PropTypes.string.isRequired,
+ errors: PropTypes.arrayOf(
+ PropTypes.shape({
+ /**
+ * the id of the element on the page to scroll too
+ */
+ id: PropTypes.string.isRequired,
+ /**
+ * the text to display for the error component
+ */
+ text: PropTypes.string.isRequired,
+ })
+ ),
+ /**
+ * onClick callback
+ */
+ onClick: PropTypes.func,
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 | 1x +1x + +1x + + + + + + + + + + + + + + + + + + +11x + +1x + + + + + + + + + + + + + + + + + | import React from "react";
+import { ErrorBox } from "./ErrorBox";
+
+export default {
+ title: "Components/Molecules/ErrorBox",
+ component: ErrorBox,
+ decorators: [
+ (Story) => (
+ <div className="w-full flex items-center flex-col">
+ <div className="w-96">
+ <Story />
+ </div>
+ <div id="someid" className="mt-80">
+ Some element with an id
+ </div>
+ </div>
+ ),
+ ],
+};
+
+const Template = (args) => <ErrorBox {...args} />;
+
+export const Primary = Template.bind({});
+
+Primary.args = {
+ text: "The form could not be submitted because three errors were found",
+ errors: [
+ {
+ id: "someid",
+ text: "Some Error 1",
+ },
+ {
+ id: "someid",
+ text: "Some Error 2",
+ },
+ {
+ id: "someid",
+ text: "Some Error 3",
+ },
+ ],
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 | 10x +10x +10x +10x +10x +10x +10x +10x +10x + + + + + +10x + + + + + +10x +10x +10x +10x +10x +10x +10x + +10x + +10x +7x +2x +2x + + + + +10x + + + +1x +1x + + + + +1x +1x + + +1x + + + + + + + +10x +10x +10x + + + + + + + +10x + +1x + +1x + +1x + +1x + +1x + + + + + + +1x + + + +1x + +1x + + + + + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +10x + + + + + + +10x + | import React, { useEffect, useState, useRef } from "react"; +import PropTypes from "prop-types"; +import { useTranslation } from "next-i18next"; +import { ActionButton } from "../atoms/ActionButton"; +import Joi from "joi"; +import { ErrorLabel } from "../atoms/ErrorLabel"; +import FocusTrap from "focus-trap-react"; +import lockScroll from "react-lock-scroll"; +import { stripFeedback } from "../../lib/utils/stripFeedback"; + +/** + * Displays the PhaseBanner on the page + */ + +export const FeedbackWidget = ({ + showFeedback, + toggleForm, + projectName, + path, +}) => { + const [submitted, setSubmitted] = useState(false); + const [feedbackClose, setFeedbackClose] = useState(false); + const { t } = useTranslation("common"); + const [response, setResponse] = useState(t("thankYouFeedback")); + const email = process.env.NEXT_PUBLIC_NOTIFY_REPORT_A_PROBLEM_EMAIL; + const [count, setCount] = useState(2000); + var maxLength = 2000; + + lockScroll(showFeedback); + + useEffect(() => { + if (!showFeedback) { + setFeedbackError(""); + setFeedback(""); + } + }, [showFeedback]); + + // Joi form validation schema. + const formSchema = Joi.object({ + feedback: Joi.string() + .required() + .error((errors) => { + errors.forEach((error) => { + switch (error.code) { + case "any.required": + error.message = t("feedbackRequired"); + break; + default: + error.message = t("feedbackRequired"); + break; + } + }); + return errors; + }), + }); + + function setFocusAfterSubmit() { + document.getElementById("feedbackButton").focus(); + } + + const [feedback, setFeedback] = useState(""); + const [feedbackError, setFeedbackError] = useState(""); + const feedbackObject = useRef({ + feedbackToSend: { + project: "", + pageUrl: "", + feedback: "", + }, + }); + + let onSubmitHandler = async (e) => { + // prevent default behaviour of form + e.preventDefault(); + // clear out error values + await setFeedbackError(""); + // compile feedback into object to be validated + const formData = { feedback }; + //Strip personal identifier information from feedback + var cleanedFeedback = stripFeedback(formData.feedback); + // set values in feedback object + feedbackObject.current.feedbackToSend = { + project: projectName, + pageUrl: path, + feedback: cleanedFeedback, + }; + + // validate data using Joi schema + const { error } = formSchema.validate(formData, { + abortEarly: false, + allowUnknown: true, + }); + const valid = error === undefined; + + Iif (valid) { + //Submit data to the api + const response = await fetch("/api/feedback", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(feedbackObject.current.feedbackToSend), + }); + + // if the response is good, show thank you message + if (response.status === 201 || response.status === 200) { + await setResponse(t("thankYouFeedback")); + setFeedback(""); + setCount(2000); + } else { + await setResponse(t("sorryFeedback")); + } + + setSubmitted(true); + setFeedbackClose(false); + setFocusAfterSubmit(); + } else { + setFeedbackError(error.message); + } + }; + + return ( + <> + {showFeedback ? ( + <FocusTrap + focusTrapOptions={{ + initialFocus: false, + fallbackFocus: "#feedbackClose", + }} + > + <div + className="fixed top-0 left-0 w-screen h-full flex justify-center items-center" + style={{ background: "rgba(71, 71, 71, 0.8)" }} + > + <div + className="w-auto mx-12 md:mx-24 bg-white shadow-lg border-black border-4" + data-testid="feedbackDropdown" + > + {submitted ? ( + <div role="status" className="w-full"> + {!feedbackClose ? ( + <div + className={`${ + response === t("thankYouFeedback") + ? "bg-custom-green-darker font-bold" + : "bg-circle-color" + } text-white flex py-2`} + > + <div className="layout-container flex"> + <span className="flex flex-col text-xs lg:text-sm font-body mt-2 mb-4 w-full"> + {response} + {response === t("sorryFeedback") ? ( + <ActionButton + id="link-mail" + ariaLabel="Service Canada email" + dataCy="link-mail" + dataTestId="link-mail" + href={`mailto:${email}`} + text={email} + custom="w-max text-xs lg:text-sm underline outline-none focus:outline-white-solid" + /> + ) : ( + "" + )} + </span> + <div className="w-1/4 flex justify-end"> + <ActionButton + id="feedbackClose" + ariaLabel="Close the expanded feedback section" + dataCy="closeButton" + dataTestId="closeButton" + custom="font-body text-gray-dark-100 flex -py-1 mt-2.5 lg:mt-0 outline-none focus:outline-white-solid items-center" + imageSource="/close-x.svg" + imageAlt="Close button" + imageSpanClass="text-xs text-white leading-4 lg:text-sm underline ml-1 lg:ml-2 lg:leading-10" + imageSpanText={t("close")} + onClick={() => setFeedbackClose(true)} + tabindex="-1" + /> + </div> + </div> + </div> + ) : ( + "" + )} + </div> + ) : ( + "" + )} + <div className="layout-container text-gray-dark-100 pb-4"> + <div className="pt-4"> + <ActionButton + id="feedbackClose" + ariaLabel="Close the expanded feedback section" + dataCy="closeButton" + dataTestId="closeButton" + custom="flex float-right font-body text-gray-dark-100 flex mt-2.5 lg:mt-0 outline-none focus:outline-white-solid items-center" + imageSource="/close-x.svg" + imageAlt="Close button" + imageSpanClass="text-xs leading-4 lg:text-sm underline ml-2 lg:leading-10" + imageSpanText={t("close")} + onClick={() => { + toggleForm(); + setCount(2000); + }} + /> + </div> + <h2 className="text-h4 lg:text-h3 lg:text-sm font-display pt-6 mb-4 w-48 sm:w-auto"> + {t("improveService")} + </h2> + <ul className="list-outside list-disc px-6 pb-3"> + <li className="text-xs lg:text-sm pt-2 pb-1 font-body"> + <strong>{t("reportAProblemNoReply")}</strong> + </li> + <li className="text-xs lg:text-sm font-body mb-0"> + <strong>{t("confidential")}</strong> + <ActionButton + ariaLabel="Privacy page link" + id="link-privacyPage" + dataCy="link-privacyPage" + dataTestId="link-privacyPage" + href={t("privacyLink")} + text={t("reportAProblemPrivacyStatement")} + custom="text-xs lg:text-sm underline ml-2 outline-none focus:outline-white-solid" + /> + </li> + </ul> + <form + data-gc-analytics-formname="ESDC|EDSC:ServiceCanadaLabsFeedback-Form" + data-gc-analytics-collect='[{"value":"input,select","emptyField":"N/A"}]' + className="w-full" + action="#" + onSubmit={onSubmitHandler} + aria-live="polite" + > + <label + htmlFor="feedbackTextArea" + className="text-xs lg:text-sm font-body" + > + <b + className="text-error-border-red mr-1" + aria-hidden="true" + > + * + </b> + <b>{t("doBetter")}</b> + </label> + <div id="feedbackInfo"> + <p className="text-xs lg:text-sm my-2"> + {t("doNotInclude")} + </p> + <p className="text-xs lg:text-sm mb-1 mt-4"> + {count} + {t("maximum2000")} + </p> + </div> + {feedbackError ? ( + <ErrorLabel + message={feedbackError} + className="text-black mt-4" + /> + ) : undefined} + <textarea + aria-describedby="feedbackInfo" + id="feedbackTextArea" + name="feedbackTextArea" + maxLength="2000" + rows="5" + className={ + "text-input font-body w-full min-h-40px shadow-sm text-form-input-gray border-2 border-gray-dark-100 my-2 py-6px px-12px rounded" + } + value={feedback} + onChange={(e) => setFeedback(e.currentTarget.value)} + onInput={(e) => + setCount(maxLength - e.currentTarget.value.length) + } + aria-required="true" + /> + <ActionButton + id="feedback-submit" + ariaLabel="Submit feedback" + custom="outline-none focus:outline-black-solid rounded block w-full lg:w-auto lg:px-12 text-xs lg:text-sm py-2 mt-2 font-bold bg-custom-blue-blue text-white border border-custom-blue-blue active:bg-custom-blue-dark hover:bg-custom-blue-light flex justify-center" + type="submit" + dataCy="feedback-submit" + dataTestId="feedback-submit" + text={t("reportAProblemSubmit")} + analyticsTracking + /> + </form> + </div> + </div> + </div> + </FocusTrap> + ) : ( + "" + )} + </> + ); +}; + +FeedbackWidget.propTypes = { + /** + * This is for showing the feedback component + */ + feedbackActive: PropTypes.bool, +}; + +export default FeedbackWidget; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 | 1x +1x + +1x + + + + + + +8x + +1x + + + | import React from "react";
+import FeedbackWidget from "./FeedbackWidget";
+
+export default {
+ title: "Components/Molecules/FeedbackWidget",
+ component: FeedbackWidget,
+};
+
+const Template = (args) => <FeedbackWidget {...args} />;
+
+export const Primary = Template.bind({});
+
+Primary.args = {
+ showFeedback: true,
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 | 1x +1x + + + + +4x + + + + + + + + + + + + +9x + + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import PropTypes from "prop-types"; +import { RadioButton } from "../atoms/RadioButton"; + +/** + * Filter Experiments component + */ +export function Filter(props) { + return ( + <form + className="my-12" + data-testid={props.dataTestId} + data-cy={props.dataCy} + > + <fieldset> + <legend className="md:float-left font-body pb-3 pt-2 pr-4 text-sm md:text-base"> + {props.label} + </legend> + <div className={"flex"}> + {props.options.map(({ id, label, checked }, index) => ( + <RadioButton + key={id} + label={label} + value={id} + name={id} + id={id} + dataTestId={id} + dataCy={id} + onChange={props.onChange} + checked={checked} + roundedFront={index === 0} + roundedBack={index === props.options.length - 1} + /> + ))} + </div> + </fieldset> + </form> + ); +} + +Filter.propTypes = { + /** + * options for the filter + */ + options: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.string.isRequired, + label: PropTypes.string.isRequired, + checked: PropTypes.bool, + }) + ).isRequired, + + /** + * filter label + */ + label: PropTypes.string, + + /** + * Action to do on input change + */ + onChange: PropTypes.func, + + /** + * Test id for unit tests + */ + dataTestId: PropTypes.string, + + /** + * Test id for cypress test + */ + dataCy: PropTypes.string, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 | 1x +1x + +1x + + + + + + +12x + +1x + + + + + + + + + + + + + + + + + + + + | import React from "react";
+import { Filter } from "./Filter";
+
+export default {
+ title: "Components/Molecules/Filter",
+ component: Filter,
+};
+
+const Template = (args) => <Filter {...args} />;
+
+export const Primary = Template.bind({});
+
+Primary.args = {
+ label: "Filter By",
+ options: [
+ {
+ id: "all",
+ label: "All",
+ checked: false,
+ },
+ {
+ id: "coming_soon",
+ label: "Coming Soon",
+ checked: false,
+ },
+ {
+ id: "alpha",
+ label: "Alpha",
+ checked: true,
+ },
+ ],
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 | 8x + +11x +10x + + + + + + + + + + + + + + + + + + + + + + +8x + + + + + + + + + + + + + + + + + + + + + + + + + + | import PropTypes from "prop-types"; + +export function Heading(props) { + const { title, fromLink, fromText, id, className } = props; + + return ( + <> + <h1 className={`mb-0 pb-2 leading-heading1 ${className}`} id={id}> + {title} + </h1> + <div className="mb-11 border-b-[6px] border-b-multi-red-red50a w-[72px]"></div> + {fromLink && fromText && ( + <p className=""> + <strong>From: </strong> + <a + href={fromLink} + className="underline text-multi-blue-blue70b font-body lg:text-browserh5 font-bold text-mobileh5 leading-[33px] hover:text-multi-blue-blue50b" + > + {fromText} + </a> + </p> + )} + </> + ); +} + +Heading.propTypes = { + /** + * The text / title that will be displayed as heading + */ + title: PropTypes.string.isRequired, + /** + * Link that should be dispayed under the main heading level + */ + fromLink: PropTypes.string, + /** + * Text that will be displyed as text link + */ + fromText: PropTypes.string, + /** + * css overrides for button + */ + className: PropTypes.string, + /** + * To identify the heading element + */ + id: PropTypes.string.isRequired, + /** + * Test id for unit test + */ + dataTestId: PropTypes.string, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 | 1x + +1x + + + + + + +3x +1x + +1x + + + + +1x + + + + + + | import { Heading } from "./Heading";
+
+export default {
+ title: "Components/Molecules/Heading",
+ component: Heading,
+};
+
+const Template = (args) => <Heading {...args} />;
+
+export const Default = Template.bind({});
+export const withFromLink = Template.bind({});
+
+Default.args = {
+ title: "Default Heading",
+ id: "withoutLink",
+};
+
+withFromLink.args = {
+ title: "Heading with from link",
+ fromLink: "https://www.google.com",
+ fromText: "Google",
+ id: "withLink",
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 | 1x + + + + +3x +2x + + + + +8x + + +8x +8x + + + + + + + + + + + + + + +1x + + + + + + + + + + + | import PropTypes from "prop-types"; + +/** + * List component + */ +export function List(props) { + let opacity = 40; + return ( + <ul className={props.className}> + {props.items.map((item, key) => { + let className = + "bg-opacity-" + + opacity + + " bg-circle-color text-shadow-about-circles flex-shrink-0 mr-4 mb-2 rounded-full h-36 w-36 flex items-center justify-center text-white font-bold font-display text-h1xxl relative md:left-0 -left-14"; + if (opacity < 100) opacity += 20; + return ( + <li key={key} className="flex"> + <span className={className} role="presentation"> + {key + 1} + </span> + <p className="text-sm md:text-p my-auto leading-normal font-body"> + {item} + </p> + </li> + ); + })} + </ul> + ); +} + +List.propTypes = { + /** + * List items + */ + items: PropTypes.arrayOf(String).isRequired, + + /** + * Option for styling component + */ + className: PropTypes.string, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 | 1x +1x + +1x + + + + + + +5x + +1x + + + | import React from "react";
+import { List } from "./List";
+
+export default {
+ title: "Components/Molecules/List",
+ component: List,
+};
+
+const Template = (args) => <List {...args}></List>;
+
+export const Primary = Template.bind({});
+
+Primary.args = {
+ items: ["Item 1", "Item 2", "Item 3", "Item 4"],
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 | 9x +9x + +13x +13x + + + + + + + + + + + + + + + + +273x + + + + + + + + + + + + + + + + + + + + + + | import { Link } from "../atoms/Link"; +import { useTranslation } from "next-i18next"; + +export function MainBand(props) { + const { t } = useTranslation("common"); + + return ( + <> + <h3 className="pt-[22px] text-multi-neutrals-white font-body font-bold text-[19px]"> + {t("footerTitle")} + </h3> + <nav + className="pb-6" + role="navigation" + aria-labelledby="accessibleSectionHeader1" + > + <h2 className="sr-only" id="accessibleSectionHeader1"> + {t("aboutGovernment")} + </h2> + <ul className="md:grid md:grid-cols-2 lg:grid-cols-3 flex flex-col gap-1 text-xs ml-0"> + {props.landscapeLinks.map((key, index) => { + return ( + <li + key={key + index} + className={`${ + index === 0 ? "footerLine pb-[22px] relative" : "" + } text-white w-64 sm:w-56 lg:w-80 my-2.5 list-none ml-0 text-xs`} + > + <Link + id={"LandscapeLink" + index} + href={t(`landscapeLinks.link.${key}`)} + text={t(`landscapeLinks.text.${key}`)} + linkStyle="smfooterWhite" + target={props.target} + /> + </li> + ); + })} + </ul> + </nav> + </> + ); +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 | 1x +1x +1x +1x + + + + +4x + +4x +4x +4x + + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +12x +12x + +12x + + + + + + + + + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import PropTypes from "prop-types"; +import Link from "next/link"; +import { useRouter } from "next/router"; +import { useState } from "react"; + +/** + * Menu component + */ +export function Menu(props) { + //Router + const { asPath } = useRouter(); + const router = useRouter(); + const [showMenu, setShowMenu] = useState(false); + + return ( + <nav + title="Menu" + className="layout-container lg:justify-end lg:flex" + data-cy="menu" + role="navigation" + aria-labelledby="mainSiteNav" + > + <h3 className="sr-only" id="mainSiteNav"> + Menu + </h3> + <div className="flex justify-between"> + <button + id="menuButton" + onClick={() => setShowMenu(!showMenu)} + className="text-h4 text-canada-footer-font focus:outline-none focus:ring-2 focus:ring-black mb-4 py-1" + aria-haspopup="true" + aria-expanded={showMenu} + aria-controls="menuDropdown" + data-testid="menuButton" + > + <span className="inline-block align-middle icon-menu" /> + <span className="inline-block align-middle pl-3 font-body text-p leading-none"> + {props.menuButtonTitle} + </span> + </button> + + <button + id="menuClose" + onClick={() => setShowMenu(!showMenu)} + className={`${ + showMenu ? "" : "hidden" + } sr-only mb-4 text-canada-footer-font outline-none focus:not-sr-only focus:outline-black-solid lg:invisible`} + aria-expanded={showMenu} + aria-controls="menuDropdown" + aria-label="Close the expanded menu options" + data-testid="menuCloseButton" + > + <img src="/close-x-menu.svg" alt="Close button"></img> + </button> + </div> + + <ul + id="menuDropdown" + className={`menuDropdown mt-2 ${showMenu ? "active" : ""}`} + role="menu" + aria-expanded={showMenu} + > + {props.items.map((item, key) => { + const exactURL = asPath === item.link; // it's exactly this url + const includesURL = asPath.includes(item.link); // it's a child of this url (eg, "/projects/app" includes "/projects") + + return ( + <li + key={key} + className={`py-3 lg:py-0 cursor-pointer text-custom-blue-projects-link list-none -my-2 -ml-2`} + role="menuitem" + aria-current={exactURL ? "page" : null} + > + <Link + href={item.link} + className={`font-body text-base ${ + includesURL + ? router.pathname !== "/signup/privacy" + ? "activePage" + : "menuLink underline" + : "menuLink underline" + }`} + > + {item.text} + </Link> + </li> + ); + })} + </ul> + </nav> + ); +} + +Menu.propTypes = { + /** + * Menu title for small screens + */ + menuButtonTitle: PropTypes.string.isRequired, + + /** + * text for sign up button + */ + signUpText: PropTypes.string.isRequired, + + /** + * Array of Items for the menu + */ + items: PropTypes.arrayOf( + PropTypes.shape({ + /** + * Text for the menu + */ + text: PropTypes.string, + + /** + * Link for the menu + */ + link: PropTypes.string, + }) + ).isRequired, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 | 1x +1x + +1x + + + + + + +6x + +1x + + + + + + + + + + + + + + + + + + | import React from "react";
+import { Menu } from "./Menu";
+
+export default {
+ title: "Components/Molecules/Menu",
+ component: Menu,
+};
+
+const Template = (args) => <Menu {...args}></Menu>;
+
+export const Primary = Template.bind({});
+
+Primary.args = {
+ menuButtonTitle: "Menu",
+ signUpText: "Sign up",
+ items: [
+ {
+ link: "#",
+ text: "Link1",
+ },
+ {
+ link: "#",
+ text: "Link2",
+ },
+ {
+ link: "#",
+ text: "Link3",
+ },
+ ],
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 | 1x +1x +1x +1x + + + + +5x +5x +5x +1x + + +1x + + +1x + + + +5x +5x + + +5x +5x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import { useState } from "react"; +import { CheckBox } from "../atoms/CheckBox"; +import { RadioField } from "../atoms/RadioField"; +import PropTypes from "prop-types"; + +/** + * An optional list field (radio, checkbox) that is enabled by a checkbox + */ +export function OptionalListField({ controlType = "checkbox", ...props }) { + let [showListField, setShowListField] = useState(props.checked || false); + let handleCheckChange = (wasChecked, name, value) => { + Iif (wasChecked) { + setShowListField(false); + } else { + setShowListField(true); + } + + Iif (props.onControlChange) { + props.onControlChange(wasChecked, name, value); + } + }; + let sortedChildren = [...props.children].sort((a, b) => { + Iif (a.props.label < b.props.label) { + return -1; + } + if (b.props.label < a.props.label) { + return 1; + } + return 0; + }); + return ( + <> + {controlType === "checkbox" ? ( + <CheckBox + label={props.controlLabel} + id={props.controlId} + name={props.controlName} + checked={props.checked} + uncontrolled={props.uncontrolled} + value={props.controlValue} + onChange={handleCheckChange} + dataTestId={props.controlDataTestId} + required={props.controlRequired} + dataCy={props.controlDataCy} + /> + ) : ( + <RadioField + label={props.controlLabel} + id={props.controlId} + name={props.controlName} + checked={props.checked} + uncontrolled={props.uncontrolled} + value={props.controlValue} + onChange={handleCheckChange} + required={props.controlRequired} + dataTestId={props.controlDataTestId} + dataCy={props.controlDataCy} + /> + )} + {(props.uncontrolled && showListField) || props.checked ? ( + <fieldset className="mb-10px"> + <legend className="block leading-tight text-sm font-body mb-5px font-bold"> + {props.listFieldRequired ? ( + <b className="text-error-border-red" aria-hidden="true"> + * + </b> + ) : ( + "" + )} + {props.listLabel} + </legend> + <div className="gap-4">{sortedChildren}</div> + </fieldset> + ) : undefined} + </> + ); +} + +OptionalListField.propTypes = { + /** + * the type of field that should be used + */ + controlType: PropTypes.oneOf(["checkbox", "radiofield"]), + /** + * the id for the checkbox + */ + controlId: PropTypes.string.isRequired, + + /** + * the name for the checkbox + */ + controlName: PropTypes.string.isRequired, + + /** + * the label for the checkbox + */ + controlLabel: PropTypes.string.isRequired, + + /** + * the value for the checkbox + */ + controlValue: PropTypes.string, + + /** + * whether or not the checkbox is checked + */ + checked: PropTypes.bool, + + /** + * boolean flag to denote whether or not the inputs are controlled + */ + uncontrolled: PropTypes.bool, + + /** + * whether or not the control is required + */ + controlRequired: PropTypes.bool, + + /** + * the test id for the checkbox to select in unit tests + */ + controlDataTestId: PropTypes.string, + + /** + * the cypress selector for the checkbox + */ + controlDataCy: PropTypes.string, + + /** + * callback when the checkbox changes + */ + onControlChange: PropTypes.func, + + /** + * whether or not the list field is required + */ + listFieldRequired: PropTypes.bool, + + /** + * list items to display + */ + children: PropTypes.arrayOf(PropTypes.element), + + /** + * legend text for the list items + */ + listLabel: PropTypes.string, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 | 1x +1x +1x +1x + +1x + + + + + + + + + + + + + + + +1x +1x + + + + + + + + + + + + + + + + + + + + + + + + +2x +1x + + + + + + + + + + + + + + + + + + + + + + + + + + +2x +1x + + + + + + + + + + + + + + + + + + + + + + + + + + +2x +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + +2x +1x + + + + + + + + + + + + + + + + + + + + + + + + + + | import React from "react"; +import { OptionalListField } from "./OptionalListField"; +import { CheckBox } from "../atoms/CheckBox"; +import { RadioField } from "../atoms/RadioField"; + +export default { + title: "Components/Molecules/OptionalListField", + component: OptionalListField, + decorators: [ + (Story) => ( + <div className="w-full flex justify-center"> + <div className="w-96"> + <Story /> + </div> + </div> + ), + ], +}; + +const Template = (args) => <OptionalListField {...args} />; + +export const UnOpened = Template.bind({}); +UnOpened.args = { + controlId: "nutella-check-1", + controlName: "nutellaCheckOne", + controlLabel: "Do you not like Nutella ?", + controlValue: "unopened", + controlDataTestId: "unopened-check-1", + listLabel: "Please check all the reasons why you are wrong.", + children: [ + <CheckBox + key="key1" + label="I don't like fake chocolate spread" + name="reasons" + value="dislike" + id="reasons-dislike" + />, + <CheckBox + key="key2" + label="I make poor choices" + name="reasons" + value="poor-choice" + id="reasons-poor-choice" + />, + ], +}; + +export const Opened_Checkboxes = Template.bind({}); +Opened_Checkboxes.args = { + controlId: "nutella-check-1", + controlName: "nutellaCheckOne", + controlLabel: "Do you not like Nutella ?", + checked: true, + controlDataTestId: "opened-check-1", + listLabel: "Please check all the reasons why you are wrong.", + children: [ + <CheckBox + key="key1" + label="I don't like fake chocolate spread" + name="reasons" + value="dislike" + id="reasons-dislike" + dataTestId="reasons-dislike" + />, + <CheckBox + key="key2" + label="I make poor choices" + name="reasons" + value="poor-choice" + id="reasons-poor-choice" + dataTestId="reasons-poor-choice" + />, + ], +}; + +export const Opened_Radiofields = Template.bind({}); +Opened_Radiofields.args = { + controlId: "nutella-check-1", + controlName: "nutellaCheckOne", + controlLabel: "Do you not like Nutella ?", + checked: true, + controlDataTestId: "opened-check-1", + listLabel: "Please check all the reasons why you are wrong.", + children: [ + <RadioField + key="key1" + label="I don't like fake chocolate spread" + name="reasons" + value="dislike" + id="reasons-dislike" + dataTestId="reasons-dislike" + />, + <RadioField + key="key2" + label="I make poor choices" + name="reasons" + value="poor-choice" + id="reasons-poor-choice" + dataTestId="reasons-poor-choice" + />, + ], +}; + +export const Radio = Template.bind({}); +Radio.args = { + controlType: "radiofield", + controlId: "nutella-check-1", + controlName: "nutellaCheckOne", + controlLabel: "Do you not like Nutella ?", + checked: true, + controlDataTestId: "radio-check-1", + listLabel: "Please check all the reasons why you are wrong.", + children: [ + <CheckBox + key="key1" + label="I don't like fake chocolate spread" + name="reasons" + value="dislike" + id="reasons-dislike" + dataTestId="reasons-dislike" + />, + <CheckBox + key="key2" + label="I make poor choices" + name="reasons" + value="poor-choice" + id="reasons-poor-choice" + dataTestId="reasons-poor-choice" + />, + ], +}; + +export const UnControlled = Template.bind({}); +UnControlled.args = { + controlId: "nutella-check-1", + controlName: "nutellaCheckOne", + controlLabel: "Do you not like Nutella ?", + uncontrolled: true, + controlDataTestId: "uncontrolled-check-1", + listLabel: "Please check all the reasons why you are wrong.", + children: [ + <CheckBox + key="key1" + label="I don't like fake chocolate spread" + name="reasons" + value="dislike" + id="reasons-dislike" + dataTestId="reasons-dislike" + />, + <CheckBox + key="key2" + label="I make poor choices" + name="reasons" + value="poor-choice" + id="reasons-poor-choice" + dataTestId="reasons-poor-choice" + />, + ], +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 | 2x +2x +2x +2x +2x +2x +2x + + + + +54x +55x +55x +55x +55x +3x + + + +3x +3x + + +3x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +2x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import { useState } from "react"; +import { CheckBox } from "../atoms/CheckBox"; +import { TextField } from "../atoms/TextField"; +import { MultiTextField } from "../atoms/MultiTextField"; +import { RadioField } from "../atoms/RadioField"; +import { useTranslation } from "next-i18next"; +import PropTypes from "prop-types"; + +/** + * An optional text box that is enabled by a checkbox + */ +export function OptionalTextField({ controlType = "checkbox", ...props }) { + let [showTextField, setShowTextField] = useState(props.checked || false); + const [expandState, setExpandState] = useState("collapsed"); + const { t } = useTranslation("common"); + let handleCheckChange = (wasChecked, name, value) => { + Iif (wasChecked) { + setShowTextField(false); + setExpandState(t("collapsed")); + } else { + setShowTextField(true); + setExpandState(t("expanded")); + } + + Iif (props.onControlChange) { + props.onControlChange(wasChecked, name, value); + } + }; + return ( + <> + {controlType === "checkbox" && ( + <CheckBox + label={props.controlLabel} + id={props.controlId} + name={props.controlName} + className={props.checkBoxStyle} + checked={props.checked} + uncontrolled={props.uncontrolled} + value={props.controlValue} + onChange={handleCheckChange} + dataTestId={props.controlDataTestId} + required={props.controlRequired} + dataCy={props.controlDataCy} + expandState={expandState} + /> + )} + {controlType === "radiofield" && ( + <RadioField + label={props.controlLabel} + id={props.controlId} + name={props.controlName} + checked={props.checked} + uncontrolled={props.uncontrolled} + value={props.controlValue} + onChange={handleCheckChange} + required={props.controlRequired} + dataTestId={props.controlDataTestId} + dataCy={props.controlDataCy} + /> + )} + {(props.uncontrolled && showTextField) || props.checked ? ( + props.multiText ? ( + <MultiTextField + label={props.textFieldLabel} + placeholder={props.textFieldPlaceHolder} + name={props.textFieldName} + id={props.textFieldId} + value={props.textFieldValue} + boldLabel={props.textLabelBold} + rows={props.rows} + cols={props.cols} + spellCheck={props.spellCheck} + wrap={props.wrap} + required={props.textFieldRequired} + onChange={ + props.onTextFieldChange ? props.onTextFieldChange : () => {} + } + dataTestId={props.textFieldDataTestId} + dataCy={props.textFieldDataCy} + error={props.error} + describedby={props.describedby} + /> + ) : ( + <TextField + label={props.textFieldLabel} + placeholder={props.textFieldPlaceHolder} + name={props.textFieldName} + id={props.textFieldId} + value={props.textFieldValue} + boldLabel={props.textLabelBold} + uncontrolled={props.uncontrolled} + required={props.textFieldRequired} + onChange={ + props.onTextFieldChange ? props.onTextFieldChange : () => {} + } + dataTestId={props.textFieldDataTestId} + describedby={props.describedby} + dataCy={props.textFieldDataCy} + /> + ) + ) : undefined} + </> + ); +} + +OptionalTextField.propTypes = { + /** + * the type of field that should be used + */ + controlType: PropTypes.oneOf(["checkbox", "radiofield"]), + /** + * the id for the checkbox + */ + controlId: PropTypes.string.isRequired, + + /** + * the id for the text field + */ + textFieldId: PropTypes.string.isRequired, + + /** + * the name for the checkbox + */ + controlName: PropTypes.string.isRequired, + + /** + * the name for the text field + */ + textFieldName: PropTypes.string.isRequired, + + /** + * the label for the checkbox + */ + controlLabel: PropTypes.string.isRequired, + + /** + * the label for the text field + */ + textFieldLabel: PropTypes.string.isRequired, + + /** + * whether or not the text label is bold + */ + textLabelBold: PropTypes.bool, + + /** + * the value for the checkbox + */ + controlValue: PropTypes.string, + + /** + * the value for the text field + */ + textFieldValue: PropTypes.string, + + /** + * text field placeholder + */ + textFieldPlaceHolder: PropTypes.string, + + /** + * whether or not the checkbox is checked + */ + checked: PropTypes.bool, + + /** + * boolean flag to denote whether or not the inputs are controlled + */ + uncontrolled: PropTypes.bool, + + /** + * whether or not the control is required + */ + controlRequired: PropTypes.bool, + + /** + * whether or not the text field is required + */ + textFieldRequired: PropTypes.bool, + + /** + * the test id for the checkbox to select in unit tests + */ + controlDataTestId: PropTypes.string, + + /** + * the test id for the text field to select in unit tests + */ + textFieldDataTestId: PropTypes.string, + + /** + * the cypress selector for the checkbox + */ + controlDataCy: PropTypes.string, + + /** + * the cypress selector for the text field + */ + textFieldDataCy: PropTypes.string, + + /** + * callback when the checkbox changes + */ + onControlChange: PropTypes.func, + + /** + * callback when the text field changes + */ + onTextFieldChange: PropTypes.func, + + /** + * whether or not its a multi text field + */ + multiText: PropTypes.bool, + + /** + * how much lines should the multi text field show + */ + rows: PropTypes.number, + + /** + * how much columns the multi text field has + */ + cols: PropTypes.number, + + /** + * the minimum amount of characters for the multi text field + */ + minLength: PropTypes.number, + + /** + * the maximum amount of characters for the multi text field + */ + maxLength: PropTypes.number, + + /** + * the wrap preference for the multi text field + */ + wrap: PropTypes.oneOf(["hard", "soft"]), + + /** + * whether or not to spellcheck for the multi text field + */ + spellCheck: PropTypes.bool, + + /** + * message to display if there is an error + */ + error: PropTypes.string, + + /** + * aria-describedby label id + */ + describedby: PropTypes.string, + + /** + * Styling for checkbox + */ + checkBoxStyle: PropTypes.string, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 | 1x +1x + +1x + + + + + + + + + + + + + + + +1x +1x + + + + + + + + + + +1x +1x + + + + + + + + + + + +2x +1x + + + + + + + + + + + + +2x +1x + + + + + + + + + + + +2x +1x + + + + + + + + + + + + + | import React from "react"; +import { OptionalTextField } from "./OptionalTextField"; + +export default { + title: "Components/Molecules/OptionalTextField", + component: OptionalTextField, + decorators: [ + (Story) => ( + <div className="w-full flex justify-center"> + <div className="w-96"> + <Story /> + </div> + </div> + ), + ], +}; + +const Template = (args) => <OptionalTextField {...args} />; + +export const UnOpened = Template.bind({}); +UnOpened.args = { + controlId: "nutella-check-1", + textFieldId: "nutella-text-1", + controlName: "nutellaCheckOne", + textFieldName: "nutellaTextOne", + controlLabel: "Do you not like Nutella ?", + textFieldLabel: "Please explain why you are wrong ?", + controlDataTestId: "unopened-check-1", + textFieldDataTestId: "unopened-text-1", +}; + +export const Opened = Template.bind({}); +Opened.args = { + controlId: "nutella-check-1", + textFieldId: "nutella-text-1", + controlName: "nutellaCheckOne", + textFieldName: "nutellaTextOne", + controlLabel: "Do you not like Nutella ?", + checked: true, + textFieldLabel: "Please explain why you are wrong ?", + controlDataTestId: "opened-check-1", + textFieldDataTestId: "opened-text-1", +}; + +export const Radio = Template.bind({}); +Radio.args = { + controlType: "radiofield", + controlId: "nutella-check-1", + textFieldId: "nutella-text-1", + controlName: "nutellaCheckOne", + textFieldName: "nutellaTextOne", + controlLabel: "Do you not like Nutella ?", + checked: true, + textFieldLabel: "Please explain why you are wrong ?", + controlDataTestId: "radio-check-1", + textFieldDataTestId: "radio-text-1", +}; + +export const UnControlled = Template.bind({}); +UnControlled.args = { + controlId: "nutella-check-1", + textFieldId: "nutella-text-1", + controlName: "nutellaCheckOne", + textFieldName: "nutellaTextOne", + controlLabel: "Do you not like Nutella ?", + uncontrolled: true, + textFieldLabel: "Please explain why you are wrong ?", + controlDataTestId: "uncontrolled-check-1", + textFieldDataTestId: "uncontrolled-text-1", +}; + +export const MultiText = Template.bind({}); +MultiText.args = { + controlId: "nutella-check-1", + textFieldId: "nutella-text-1", + controlName: "nutellaCheckOne", + textFieldName: "nutellaTextOne", + controlLabel: "Do you not like Nutella ?", + uncontrolled: true, + multiText: true, + rows: 5, + textFieldLabel: "Please explain why you are wrong ?", + controlDataTestId: "multitext-check-1", + textFieldDataTestId: "multitext-text-1", +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 | 1x + + + + +3x + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + + + + | import PropTypes from "prop-types"; + +/** + * Quote component + */ +export function Quote(props) { + return ( + <figure + title="Quote" + className={ + props.className + + " border-l-4 text-sm md:text-p pl-4 leading-normal font-body" + } + > + <blockquote className="max-w-sm">{props.text}</blockquote> + <figcaption className="text-gray-500 pt-4"> — {props.author}</figcaption> + </figure> + ); +} + +Quote.propTypes = { + /** + * Option for styling component + */ + className: PropTypes.string, + + /** + * Quote + */ + text: PropTypes.string, + + /** + * Author + */ + author: PropTypes.string, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 | 1x +1x + +1x + + + + + + +5x + +1x + + + + | import React from "react";
+import { Quote } from "./Quote";
+
+export default {
+ title: "Components/Molecules/Quote",
+ component: Quote,
+};
+
+const Template = (args) => <Quote {...args}></Quote>;
+
+export const Primary = Template.bind({});
+
+Primary.args = {
+ text: "Some quote",
+ author: "Author",
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 | 9x +9x + +9x + + + + + + + + + + + + + + + + + + + + + + +9x + + + + + + + + + + + + + + + + + + + + + + +9x +13x + + +13x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +65x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import { Link } from "../atoms/Link"; +import { Image } from "../atoms/Image"; + +const brandLinksDefaultEn = [ + { + href: "https://www.canada.ca/en/social.html", + text: "Social media", + }, + { + href: "https://www.canada.ca/en/mobile.html", + text: "Mobile applications", + }, + { + href: "https://www.canada.ca/en/government/about.html", + text: "About Canada.ca", + }, + { + href: "https://www.canada.ca/en/transparency/terms.html", + text: "Terms and conditions", + }, + { + href: "https://www.canada.ca/en/transparency/privacy.html", + text: "Privacy", + }, +]; + +const brandLinksDefaultFr = [ + { + href: "https://www.canada.ca/fr/sociaux.html", + text: "Médias sociaux", + }, + { + href: "https://www.canada.ca/fr/mobile.html", + text: "Applications mobiles", + }, + { + href: "https://www.canada.ca/fr/gouvernement/a-propos.html", + text: "À propos de Canada.ca", + }, + { + href: "https://www.canada.ca/fr/transparence/avis.html", + text: "Avis", + }, + { + href: "https://www.canada.ca/fr/transparence/confidentialite.html", + text: "Confidentialité", + }, +]; + +const brandLinksDefaults = (locale) => { + return locale === "en" ? brandLinksDefaultEn : brandLinksDefaultFr; +}; + +export function SubFooterBand(props) { + return ( + <div className="bg-[#F8F8F8]"> + <div + className={`lg:container mx-auto ${ + props.isAuthenticated ? "min-h-[86px]" : "min-h-[96px]" + } ${props.error ? "items-center" : ""} flex justify-between`} + > + {props.error ? ( + <div> + <a + id="top_btn" + href={props.btnLink} + className="sm:hidden float-left cursor-pointer pr-3" + > + Top of page / Haut de la page + </a> + <img src="/upArrow.svg" alt="" className="pt-2 sm:hidden" /> + </div> + ) : ( + <section className="flex items-center"> + <nav role="navigation"> + <ul className="flex flex-col md:flex-row whitespace-nowrap pt-4"> + {props.brandLinks + ? props.brandLinks.map(({ href, text, onClick }, index) => { + return ( + <li + key={index} + className={`${ + index === 0 ? "" : "md:list-disc" + } pr-4 mb-[17px] list-inside list-none text-xxs ml-6`} + > + <Link + onClick={onClick ? onClick : undefined} + id={"footerLink" + index} + href={href} + text={text} + linkStyle="smfooterBlue" + target={props.target} + /> + </li> + ); + }) + : brandLinksDefaults(props.locale).map( + ({ href, text }, index) => { + return ( + <li + key={index} + className={`${ + index === 0 ? "" : "md:list-disc" + } pr-4 mb-[17px] list-inside list-none text-xxs ml-6`} + > + <Link + onClick={ + props.onClick ? props.onClick : undefined + } + id={"footerLink" + index} + href={href} + text={text} + linkStyle="smfooterBlue" + target={props.target} + /> + </li> + ); + } + )} + </ul> + </nav> + </section> + )} + <div + className={`${ + props.error ? "items-center" : "items-center" + } min-h-[96px] flex mr-[5px]`} + > + <Image + className={`${ + props.error + ? "h-[40px] w-auto" + : "h-[25px] md:h-[40px] w-full mr-2" + } my-[15px]`} + src={props.logo} + alt="Symbol of the Government of Canada" + /> + </div> + </div> + </div> + ); +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 | 1x +1x + + + + +7x + + +6x +5x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import PropTypes from "prop-types"; +import { ActionButton } from "../atoms/ActionButton"; + +/** + * component + */ +export function TextButtonField(props) { + //Verification for styling + let secondary; + if (props.custom === undefined) + props.secondary === undefined + ? (secondary = true) + : (secondary = props.secondary); + + return ( + <div className={props.className + " mb-4 mx-0"}> + {props.html === undefined ? ( + <div className="textbuttonField">{props.children}</div> + ) : ( + <div + className="textbuttonField" + dangerouslySetInnerHTML={{ __html: props.html }} + /> + )} + + {props.buttonText ? ( + <ActionButton + id={props.idButton} + className={"mt-2 text-xs md:text-base"} + text={props.buttonText} + secondary={secondary} + disabled={props.disabled} + custom={props.custom} + href={props.href} + dataCyButton={props.dataCyButton} + /> + ) : ( + "" + )} + </div> + ); +} + +TextButtonField.propTypes = { + /** + * Option for styling component + */ + className: PropTypes.string, + + /** + * Option for html + */ + html: PropTypes.string, + + /** + * Contenty + */ + children: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.element, + PropTypes.arrayOf(PropTypes.element), + ]), + + /** + * Button id + */ + idButton: PropTypes.string, + + /** + * Button link + */ + href: PropTypes.string, + + /** + * Button text + */ + buttonText: PropTypes.string, + + /** + * Button secondary + */ + secondary: PropTypes.bool, + + /** + * Button disabled + */ + disabled: PropTypes.bool, + + /** + * Button custom + */ + custom: PropTypes.string, + + /** + * Test id for cypress test for the button + */ + dataCyButton: PropTypes.string, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 | 1x +1x + +1x + + + + + + +8x +3x +3x +3x + +1x + + + + + + + +1x + + + + + + +1x + + + + + + + +1x + + + + + + + | import React from "react";
+import { TextButtonField } from "./TextButtonField";
+
+export default {
+ title: "Components/Molecules/TextButtonField",
+ component: TextButtonField,
+};
+
+const Template = (args) => <TextButtonField {...args}></TextButtonField>;
+
+export const Primary = Template.bind({});
+export const Secondary = Template.bind({});
+export const Disabled = Template.bind({});
+export const Custom = Template.bind({});
+
+Primary.args = {
+ title: "Primary",
+ html: "<h1>Title</h1><p>Text</p>",
+ idButton: "Button1",
+ buttonText: "Button",
+ secondary: false,
+};
+
+Secondary.args = {
+ title: "Secondary",
+ html: "<h1>Title</h1><p>Text</p>",
+ buttonText: "Button",
+ idButton: "Button2",
+};
+
+Disabled.args = {
+ title: "Disabled",
+ html: "<h1>Title</h1><p>Text</p>",
+ buttonText: "Button",
+ idButton: "Button3",
+ disabled: true,
+};
+
+Custom.args = {
+ title: "Custom",
+ html: "<h1>Title</h1><p>Text</p>",
+ buttonText: "Button",
+ idButton: "Button4",
+ custom: "bg-red-100",
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 | 9x +9x + +5x + + + + + + + + + +3x +3x + + +3x + + + +3x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import Link from "next/link"; +import React, { useState } from "react"; + +export function TopNavBar({ + homeLink, + homeLinkLabel, + updatesLink, + updatesLinkLabel, + projectsLink, + projectsLinkLabel, + navAriaLabel, + buttonAriaLabel, +}) { + const [isOpen, setIsOpen] = useState(false); + const [isTransitioningClosed, setIsTransitioningClosed] = useState(false); + + //Handles the opening and closing of our nav + const handleClick = () => { + isOpen ? animateCloseMenu() : setIsOpen(!isOpen); + }; + + const animateCloseMenu = () => { + setIsTransitioningClosed(true); + setTimeout(() => { + setIsTransitioningClosed(false); + setIsOpen(!isOpen); + }, 250); + }; + + return ( + <nav + aria-label={navAriaLabel} + className="bg-custom-gray-lightest min-h-[64px] flex justify-end" + > + {/* Desktop Nav Menu */} + <div className="hidden lg:flex w-full self-center justify-between layout-container"> + <Link href={homeLink} className="font-body font-semibold text-h3"> + {homeLinkLabel} + </Link> + <div className="lg:mr-16"> + <Link href={projectsLink} className="font-body mr-10 text-p"> + {projectsLinkLabel} + </Link> + <Link href={updatesLink} className="font-body text-p"> + {updatesLinkLabel} + </Link> + </div> + </div> + {/* Mobile Nav Menu */} + <div className="static lg:hidden mt-5 flex flex-col w-full mr-4"> + <button + aria-label={buttonAriaLabel} + aria-haspopup="true" + aria-expanded={isOpen ? "true" : "false"} + aria-controls="menu" + onClick={handleClick} + className="self-end" + > + {isOpen ? ( + <div + className={`${ + isTransitioningClosed ? "fade-out" : "fade-in" + } -mt-1 p-1.5`} + > + <svg + width="20" + height="20" + viewBox="0 0 17 17" + fill="none" + xmlns="http://www.w3.org/2000/svg" + className="exit-icon" + > + <path d="M11.3775 8.25L16.0683 3.55922C16.6439 2.98359 16.6439 2.05031 16.0683 1.47422L15.0258 0.431719C14.4502 -0.143906 13.5169 -0.143906 12.9408 0.431719L8.25 5.1225L3.55922 0.431719C2.98359 -0.143906 2.05031 -0.143906 1.47422 0.431719L0.431719 1.47422C-0.143906 2.04984 -0.143906 2.98312 0.431719 3.55922L5.1225 8.25L0.431719 12.9408C-0.143906 13.5164 -0.143906 14.4497 0.431719 15.0258L1.47422 16.0683C2.04984 16.6439 2.98359 16.6439 3.55922 16.0683L8.25 11.3775L12.9408 16.0683C13.5164 16.6439 14.4502 16.6439 15.0258 16.0683L16.0683 15.0258C16.6439 14.4502 16.6439 13.5169 16.0683 12.9408L11.3775 8.25Z" /> + </svg> + </div> + ) : ( + <div className={`${isTransitioningClosed ? "fade-in" : ""} -mt-1`}> + <svg + width="32" + height="32" + viewBox="0 0 24 24" + fill="none" + xmlns="http://www.w3.org/2000/svg" + > + <path + d="M4 18L20 18" + stroke="#000000" + strokeWidth="2" + strokeLinecap="round" + /> + <path + d="M4 12L20 12" + stroke="#000000" + strokeWidth="2" + strokeLinecap="round" + /> + <path + d="M4 6L20 6" + stroke="#000000" + strokeWidth="2" + strokeLinecap="round" + /> + </svg> + </div> + )} + </button> + {isOpen ? ( + <ul + id="menu" + className={`${ + isTransitioningClosed ? "fade-out" : "fade-in" + } absolute w-full flex flex-col mt-8 pb-4 bg-custom-gray-lightest drop-shadow-xl`} + > + <li + className={`${ + isTransitioningClosed ? "decrease-margin" : "expand-margin" + } my-2 ml-4`} + > + <Link href={homeLink}>{homeLinkLabel}</Link> + </li> + <li + className={`${ + isTransitioningClosed ? "decrease-margin" : "expand-margin" + } my-2 ml-4`} + > + <Link href={projectsLink}>{projectsLinkLabel}</Link> + </li> + <li + className={`${ + isTransitioningClosed ? "decrease-margin" : "expand-margin" + } my-2 ml-4`} + > + <Link href={updatesLink}>{updatesLinkLabel}</Link> + </li> + </ul> + ) : ( + "" + )} + </div> + </nav> + ); +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 | 1x +1x + +1x + + + + + + +6x + +1x + + + + + + + + + + | import React from "react";
+import { TopNavBar } from "./TopNavBar";
+
+export default {
+ title: "Components/Molecules/TopNavBar",
+ component: TopNavBar,
+};
+
+const Template = (args) => <TopNavBar {...args}></TopNavBar>;
+
+export const Primary = Template.bind({});
+
+Primary.args = {
+ homeLink: "#home",
+ homeLinkLabel: "Home",
+ updatesLink: "#updates",
+ updatesLinkLabel: "Updates",
+ projectsLink: "#projects",
+ projectsLinkLabel: "Projects",
+ navAriaLabel: "nav-aria-label",
+ buttonAriaLabel: "button-aria-label",
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +File | ++ | Statements | ++ | Branches | ++ | Functions | ++ | Lines | ++ |
---|---|---|---|---|---|---|---|---|---|
CTA.js | +
+
+ |
+ 100% | +6/6 | +66.66% | +2/3 | +100% | +2/2 | +100% | +5/5 | +
CTA.stories.js | +
+
+ |
+ 90% | +9/10 | +100% | +0/0 | +100% | +0/0 | +100% | +7/7 | +
Card.js | +
+
+ |
+ 91.66% | +11/12 | +64.28% | +9/14 | +100% | +1/1 | +100% | +10/10 | +
Card.stories.js | +
+
+ |
+ 80% | +16/20 | +100% | +0/0 | +100% | +0/0 | +100% | +14/14 | +
Collapse.js | +
+
+ |
+ 100% | +5/5 | +100% | +1/1 | +100% | +1/1 | +100% | +5/5 | +
Collapse.stories.js | +
+
+ |
+ 90% | +9/10 | +100% | +0/0 | +100% | +0/0 | +100% | +7/7 | +
ContextualAlert.js | +
+
+ |
+ 100% | +11/11 | +81.25% | +13/16 | +100% | +1/1 | +100% | +11/11 | +
ContextualAlert.stories.js | +
+
+ |
+ 93.33% | +14/15 | +100% | +0/0 | +100% | +0/0 | +100% | +10/10 | +
CopyToClipboard.js | +
+
+ |
+ 100% | +7/7 | +75% | +3/4 | +100% | +2/2 | +100% | +7/7 | +
CopyToClipboard.stories.js | +
+
+ |
+ 85.71% | +6/7 | +100% | +0/0 | +100% | +0/0 | +100% | +5/5 | +
Details.js | +
+
+ |
+ 100% | +3/3 | +100% | +0/0 | +100% | +1/1 | +100% | +3/3 | +
Details.stories.js | +
+
+ |
+ 85.71% | +6/7 | +100% | +0/0 | +100% | +0/0 | +100% | +5/5 | +
ErrorBox.js | +
+
+ |
+ 100% | +6/6 | +0% | +0/1 | +100% | +3/3 | +100% | +6/6 | +
ErrorBox.stories.js | +
+
+ |
+ 85.71% | +6/7 | +100% | +0/0 | +100% | +0/0 | +100% | +5/5 | +
FeedbackWidget.js | +
+
+ |
+ 72.58% | +45/62 | +38.09% | +8/21 | +50% | +5/10 | +71.66% | +43/60 | +
FeedbackWidget.stories.js | +
+
+ |
+ 85.71% | +6/7 | +100% | +0/0 | +100% | +0/0 | +100% | +5/5 | +
Filter.js | +
+
+ |
+ 100% | +5/5 | +100% | +0/0 | +100% | +2/2 | +100% | +5/5 | +
Filter.stories.js | +
+
+ |
+ 85.71% | +6/7 | +100% | +0/0 | +100% | +0/0 | +100% | +5/5 | +
Heading.js | +
+
+ |
+ 100% | +4/4 | +100% | +2/2 | +100% | +1/1 | +100% | +4/4 | +
Heading.stories.js | +
+
+ |
+ 88.88% | +8/9 | +100% | +0/0 | +100% | +0/0 | +100% | +6/6 | +
List.js | +
+
+ |
+ 100% | +8/8 | +100% | +1/1 | +100% | +2/2 | +100% | +7/7 | +
List.stories.js | +
+
+ |
+ 85.71% | +6/7 | +100% | +0/0 | +100% | +0/0 | +100% | +5/5 | +
MainBand.js | +
+
+ |
+ 100% | +5/5 | +100% | +2/2 | +100% | +2/2 | +100% | +5/5 | +
Menu.js | +
+
+ |
+ 92.85% | +13/14 | +60% | +6/10 | +75% | +3/4 | +92.85% | +13/14 | +
Menu.stories.js | +
+
+ |
+ 85.71% | +6/7 | +100% | +0/0 | +100% | +0/0 | +100% | +5/5 | +
OptionalListField.js | +
+
+ |
+ 78.94% | +15/19 | +75% | +12/16 | +100% | +3/3 | +78.94% | +15/19 | +
OptionalListField.stories.js | +
+
+ |
+ 90.47% | +19/21 | +100% | +0/0 | +100% | +0/0 | +100% | +15/15 | +
OptionalTextField.js | +
+
+ |
+ 85% | +17/20 | +78.94% | +15/19 | +50% | +2/4 | +85% | +17/20 | +
OptionalTextField.stories.js | +
+
+ |
+ 84.21% | +16/19 | +100% | +0/0 | +100% | +0/0 | +100% | +13/13 | +
Quote.js | +
+
+ |
+ 100% | +3/3 | +100% | +0/0 | +100% | +1/1 | +100% | +3/3 | +
Quote.stories.js | +
+
+ |
+ 85.71% | +6/7 | +100% | +0/0 | +100% | +0/0 | +100% | +5/5 | +
SubFooterBand.js | +
+
+ |
+ 88.88% | +8/9 | +42.85% | +9/21 | +75% | +3/4 | +88.88% | +8/9 | +
TextButtonField.js | +
+
+ |
+ 100% | +6/6 | +66.66% | +4/6 | +100% | +1/1 | +100% | +6/6 | +
TextButtonField.stories.js | +
+
+ |
+ 93.75% | +15/16 | +100% | +0/0 | +100% | +0/0 | +100% | +11/11 | +
TopNavBar.js | +
+
+ |
+ 58.33% | +7/12 | +15.78% | +3/19 | +25% | +1/4 | +58.33% | +7/12 | +
TopNavBar.stories.js | +
+
+ |
+ 85.71% | +6/7 | +100% | +0/0 | +100% | +0/0 | +100% | +5/5 | +
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 | 8x +8x +8x +8x + + +12x +12x + +12x +12x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +12x + | import { useState } from "react"; +import Image from "next/image"; +import { useRouter } from "next/router"; +import { useTranslation } from "next-i18next"; + +function Feedback() { + const [isSubmitted, setIsSubmitted] = useState(false); + const [isProvidingFeedback, setIsProvidingFeedback] = useState(false); + + const router = useRouter(); + const { t } = useTranslation("common"); + + async function handleSubmit(e) { + e.preventDefault(); + try { + await fetch("/api/submit-feedback", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(Object.fromEntries(new FormData(e.target))), + }); + } finally { + setIsSubmitted(true); + } + } + + return ( + <div className="sm:flex items-center justify-between gap-20 bg-gray-light-200 p-5 max-w-[568px] border rounded"> + {isSubmitted && ( + <div className="flex gap-5 items-center"> + <Image + src="/success_img.svg" + alt="" + width={25} + height={25} + style={{ width: 25, height: 25 }} + priority + ></Image> + <p>{t("feedback.thank-you")}</p> + </div> + )} + + {isProvidingFeedback && !isSubmitted && ( + <form onSubmit={handleSubmit} className="space-y-5"> + <input type="hidden" name="page" value={router.asPath} /> + <fieldset> + <legend className="font-bold mb-2"> + {t("feedback.what-was-wrong")} + </legend> + <label className="flex gap-2"> + <input + type="radio" + name="what-was-wrong" + value="cant-find-info" + required + ></input> + {t("feedback.cant-find-info")} + </label> + <label className="flex gap-2"> + <input + type="radio" + name="what-was-wrong" + value="hard-to-understand" + ></input> + {t("feedback.hard-to-understand")} + </label> + <label className="flex gap-2"> + <input + type="radio" + name="what-was-wrong" + value="there-was-an-error" + ></input> + {t("feedback.there-was-an-error")} + </label> + <label className="flex gap-2"> + <input + type="radio" + name="what-was-wrong" + value="other-reason" + ></input> + + {t("feedback.other-reason")} + </label> + </fieldset> + <label className="flex flex-col gap-2"> + <span className="font-bold"> + {t("feedback.provide-more-details")} + </span> + <span id="extra-info" className="font-[500] text-xs"> + {t("feedback.no-protected-info")} + </span> + <span id="maximum-characters" className="font-[300] text-xs"> + {t("feedback.maximum-characters")} + </span> + <textarea + name="extra-details" + aria-describedby="extra-info maximum-characters" + maxLength={300} + className="p-1" + ></textarea> + </label> + <button className="bg-multi-blue-blue70 hover:bg-multi-blue-blue60e text-white rounded py-1 px-2"> + {t("feedback.submit")} + </button> + </form> + )} + + {!isSubmitted && !isProvidingFeedback && ( + <> + <p className="font-semibold text-sm">{t("feedback.did-you-find")}</p> + <div className="flex gap-2"> + <button + onClick={() => setIsSubmitted(true)} + className="bg-multi-blue-blue70 hover:bg-multi-blue-blue60e text-white rounded py-1 px-2" + > + {t("feedback.yes")} + </button> + <button + onClick={() => setIsProvidingFeedback(true)} + className="bg-multi-blue-blue70 hover:bg-multi-blue-blue60e text-white rounded py-1 px-2" + > + {t("feedback.no")} + </button> + </div> + </> + )} + </div> + ); +} + +export default Feedback; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 | +9x +9x +9x +9x + +9x + + + + + + + + + + + + + + + + + + + + + + + +14x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +9x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | /* eslint-disable no-prototype-builtins */ +import PropTypes from "prop-types"; +import { MainBand } from "../molecules/MainBand"; +import { SubFooterBand } from "../molecules/SubFooterBand"; +import { Link } from "../atoms/Link"; + +const landscapeLinkKeys = [ + "contacts", + "departments", + "about", + "jobs", + "taxes", + "canadaAndWorld", + "immigration", + "environment", + "finance", + "travel", + "nationalSecurity", + "innovation", + "business", + "culture", + "indigenous", + "benefit", + "policing", + "veterans", + "health", + "transport", + "youth", +]; + +export const Footer = ({ + error, + id, + brandLinks, + target, + onClick, + btnLink, + preFooterTitle, + preFooterLink, + preFooterLinkText, + lang, +}) => { + return ( + <footer id={id} data-testid="footer"> + {preFooterTitle && preFooterLink ? ( + <div className="bg-multi-blue-blue70c"> + <div className="lg:container mx-auto px-6 pb-[22px]"> + <h3 className="pt-[22px] text-multi-neutrals-white font-body font-bold text-[19px]"> + {preFooterTitle} + </h3> + <Link + id="" + href={preFooterLink} + text={preFooterLinkText} + linkStyle="smfooterWhite" + /> + </div> + </div> + ) : ( + "" + )} + <div + className="bg-multi-blue-blue70 bg-no-repeat bg-clip-border sm:bg-right-bottom bg-bottom" + style={{ + backgroundImage: `url(/footer_bg_img.svg)`, + }} + > + <div className="lg:container mx-auto px-6"> + <MainBand landscapeLinks={landscapeLinkKeys} target={target} /> + </div> + </div> + <SubFooterBand + locale={lang} + container="container" + brandLinks={brandLinks} + onClick={onClick} + target={target} + logo="/wmms-blk.svg" + error={error} + btnLink={btnLink} + /> + </footer> + ); +}; + +Footer.propTypes = { + /** + * id of this component + */ + id: PropTypes.string.isRequired, + /** + * Add the path Link to the top of your page for the "to the Top" button in mobile + */ + btnLink: PropTypes.string.isRequired, + + /** + * If true will display the error page version of the footer component + */ + error: PropTypes.bool, + + /** + * Allow user to pass in their own contact link + */ + contactLink: PropTypes.string, + + /** + * List of links to display on the footer + */ + brandLinks: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.string, + text: PropTypes.string, + href: PropTypes.string, + }).isRequired + ), + + /** + * Specifies where to open the linked document + */ + target: PropTypes.string, + + /** + * Handle onclick on the footer media link + */ + onClick: PropTypes.func, + + /** + * List of menu items to display in dropdown with links + */ + contextualBandLinks: PropTypes.arrayOf( + PropTypes.shape({ + key: PropTypes.string, + text: PropTypes.string, + link: PropTypes.string, + }) + ), + preFooterTitle: PropTypes.string, + preFooterLink: PropTypes.string, + preFooterLinkText: PropTypes.string, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 | 1x +1x + +1x + + + + + + +1x +1x + + + + + | import React from "react";
+import { Footer } from "./Footer";
+
+export default {
+ title: "Components/Organisms/Footer",
+ component: Footer,
+};
+
+const Template = (args) => <Footer {...args} />;
+
+export const DefaultFooter = Template.bind({});
+DefaultFooter.args = {
+ id: "footer",
+ btnLink: "/",
+ target: "_blank",
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 | 8x +8x +8x + +10x +9x +9x +9x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import { useState } from "react"; +import { Modal } from "react-bootstrap"; +import { DSButton } from "../atoms/DSButton"; + +export const HelpIcon = ({ title, body, lang }) => { + const [showModal, setShowModal] = useState(false); + const handleClose = () => setShowModal(false); + const handleShow = () => setShowModal(true); + + return ( + <> + <button + onClick={handleShow} + className="info" + aria-label={`Help button ${title}`} + aria-expanded={showModal} + > + <svg + width="26" + height="26" + viewBox="0 0 26 26" + fill="none" + xmlns="http://www.w3.org/2000/svg" + className="help-icon" + > + <path d="M26 13C26 20.1813 20.1792 26 13 26C5.8208 26 0 20.1813 0 13C0 5.8229 5.8208 0 13 0C20.1792 0 26 5.8229 26 13ZM13.3489 4.29839C10.4922 4.29839 8.67016 5.50178 7.23943 7.64054C7.05407 7.91763 7.11608 8.29133 7.38175 8.49277L9.20065 9.87193C9.47349 10.0788 9.86223 10.0296 10.0742 9.76069C11.0106 8.57298 11.6527 7.88424 13.078 7.88424C14.1489 7.88424 15.4735 8.57345 15.4735 9.61187C15.4735 10.3969 14.8254 10.8001 13.768 11.3929C12.5349 12.0841 10.9032 12.9445 10.9032 15.0968V15.3065C10.9032 15.6538 11.1849 15.9355 11.5323 15.9355H14.4677C14.8151 15.9355 15.0968 15.6538 15.0968 15.3065V15.2366C15.0968 13.7446 19.4573 13.6825 19.4573 9.64516C19.4573 6.60473 16.3035 4.29839 13.3489 4.29839ZM13 17.2984C11.6704 17.2984 10.5887 18.3801 10.5887 19.7097C10.5887 21.0392 11.6704 22.121 13 22.121C14.3296 22.121 15.4113 21.0392 15.4113 19.7097C15.4113 18.3801 14.3296 17.2984 13 17.2984Z" /> + </svg> + </button> + + {showModal && ( + <div className="modal-bg"> + <Modal + show={showModal} + onHide={handleClose} + className="modal __variable_a1e2e3 __variable_3e745e" + aria-label={title} + > + <Modal.Header className="modal-header"> + <h2 className="modal-title">{title}</h2> + <button + onClick={handleClose} + className="modal-exit" + aria-label={lang === "en" ? "Close" : "Fermer"} + > + <svg + width="17" + height="17" + viewBox="0 0 17 17" + fill="none" + xmlns="http://www.w3.org/2000/svg" + className="exit-icon" + > + <path d="M11.3775 8.25L16.0683 3.55922C16.6439 2.98359 16.6439 2.05031 16.0683 1.47422L15.0258 0.431719C14.4502 -0.143906 13.5169 -0.143906 12.9408 0.431719L8.25 5.1225L3.55922 0.431719C2.98359 -0.143906 2.05031 -0.143906 1.47422 0.431719L0.431719 1.47422C-0.143906 2.04984 -0.143906 2.98312 0.431719 3.55922L5.1225 8.25L0.431719 12.9408C-0.143906 13.5164 -0.143906 14.4497 0.431719 15.0258L1.47422 16.0683C2.04984 16.6439 2.98359 16.6439 3.55922 16.0683L8.25 11.3775L12.9408 16.0683C13.5164 16.6439 14.4502 16.6439 15.0258 16.0683L16.0683 15.0258C16.6439 14.4502 16.6439 13.5169 16.0683 12.9408L11.3775 8.25Z" /> + </svg> + </button> + </Modal.Header> + <Modal.Body> + <p + className="modal-body" + dangerouslySetInnerHTML={{ __html: body }} + /> + </Modal.Body> + <Modal.Footer> + <DSButton + onClick={handleClose} + styling="primary" + text={lang === "en" ? "Close" : "Fermer"} + className="modal-close" + /> + </Modal.Footer> + </Modal> + </div> + )} + </> + ); +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 | 1x +1x + +1x + + + + + + +1x +1x +1x + +1x + + + + + +1x + + + + + +1x + + + + + | import * as React from "react"; +import { HelpIcon } from "./HelpIcon"; + +export default { + title: "Components/Organisms/HelpIcon", + component: HelpIcon, +}; + +const Template = (args) => <HelpIcon {...args} />; + +export const Default = Template.bind({}); +export const SampleEN = Template.bind({}); +export const SampleFR = Template.bind({}); + +Default.args = { + lang: "en", + title: "Descriptive title / Term requiring explanation", + body: "Description", +}; + +SampleEN.args = { + lang: "en", + title: "Separated", + body: "You are separated when you start living separate and apart from your spouse or common law partner because of a breakdown in the relationship for a period of at least 90 days.<br><br>Refer to marital status for more information", +}; + +SampleFR.args = { + lang: "fr", + title: "Séparé", + body: "Vous êtes considéré séparé lorsque vous vivez séparément de votre époux ou conjoint en raison de la rupture de votre union pour une période de 90 jours ou plus.<br><br>Voir état civil pour plus d’information", +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 | 8x +8x +8x +8x +8x +8x +8x +8x +8x +8x + + + + +15x + + + + + + + + + + + + + + + + +12x +12x +12x + + + + +12x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +8x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import PropTypes from "prop-types"; +import { Banner } from "../atoms/Banner"; +import { PhaseBanner } from "./PhaseBanner"; +import Link from "next/link"; +import { useTranslation } from "next-i18next"; +import { DateModified } from "../atoms/DateModified"; +import { Breadcrumb } from "../atoms/Breadcrumb"; +import { Footer } from "../organisms/Footer"; +import Feedback from "./Feedback"; +import { TopNavBar } from "../molecules/TopNavBar"; + +/** + * Component which defines the layout of the page for all screen sizes + */ +export const Layout = ({ + bannerText, + bannerTitle, + children, + locale, + langUrl, + breadcrumbItems, + feedbackActive, + showDisclaimer, + projectName, + path, + excludeFooterFeedback, + preFooterTitle, + preFooterLink, + preFooterLinkText, + dateModifiedOverride, +}) => { + const { t } = useTranslation("common"); + const language = locale === "en" ? "fr" : "en"; + path = + typeof window !== "undefined" && window.location.origin + ? window.location.href + : ""; + + const isTopNavBarActive = false; + + return ( + <div className="overflow-x-hidden"> + <nav className="skip-main" aria-label={t("skipToMainContentBtn")}> + <a + id="skipToMainContent" + className="bg-white text-custom-blue-dark text-lg underline py-1 px-2 focus:outline-dark-goldenrod hover:bg-gray-dark" + href="#pageMainTitle" + data-cy-button={"skip-Content"} + draggable="false" + aria-label={t("skipToMainContentBtn")} + > + {t("skipToMainContentBtn")} + </a> + </nav> + <header> + <h2 className="sr-only">{t("globalHeader")}</h2> + <h3 className="sr-only">{t("testSiteNotice")}</h3> + {showDisclaimer ? ( + <PhaseBanner + phase={t("phaseBannerTag")} + feedbackActive={feedbackActive} + text={t("phaseBannerText")} + projectName={projectName} + path={path} + /> + ) : ( + "" + )} + <div className="layout-container lg:max-w-full pt-4 pb-3 !mx-0 !px-5 flex-col flex lg:flex lg:flex-row justify-between bg-custom-gray-lightest"> + <div + className="flex flex-row justify-between" + role="navigation" + aria-labelledby="officialSiteNav" + > + <h3 className="sr-only" id="officialSiteNav"> + {t("officialSiteNavigation")} + </h3> + <a href="https://www.canada.ca"> + <img + src={language === "en" ? "/sig-blk-fr.svg" : "/sig-blk-en.svg"} + alt={t("symbol")} + width="375" + height="35" + className="max-w-[280px]" + /> + </a> + <h3 className="sr-only">{t("languageSelection")}</h3> + <Link + key={language} + href={langUrl} + locale={language} + data-testid="languageLink1" + className="block lg:hidden ml-6 -mt-1 sm:ml-16 underline underline-offset-[6px] font-body text-canada-footer-font lg:text-sm text-lg hover:text-canada-footer-hover-font-blue" + > + {language === "en" ? "EN" : "FR"} + </Link> + </div> + <div className="flex flex-col justify-center"> + <Link + key={language} + href={langUrl} + locale={language} + data-testid="languageLink3" + className="flex lg:block hidden underline underline-offset-[5px] font-body text-canada-footer-font hover:text-canada-footer-hover-font-blue" + data-cy="toggle-language-link" + lang={language} + > + {language === "en" ? "English" : "Français"} + </Link> + </div> + </div> + <div className="border-b-[3px] border-multi-blue-blue35" /> + {isTopNavBarActive ? ( + <TopNavBar + homeLink={t("topNavBar.homeLink")} + homeLinkLabel={t("topNavBar.homeLinkLabel")} + updatesLink={t("topNavBar.updatesLink")} + updatesLinkLabel={t("topNavBar.updatesLinkLabel")} + projectsLink={t("topNavBar.projectsLink")} + projectsLinkLabel={t("topNavBar.projectsLinkLabel")} + navAriaLabel={t("topNavBar.ariaLabel")} + buttonAriaLabel={t("topNavBar.buttonAriaLabel")} + /> + ) : null} + <div className="layout-container mt-4"> + <Breadcrumb items={breadcrumbItems} /> + </div> + </header> + + {bannerText && bannerTitle ? ( + <Banner siteTitle={bannerTitle} headline={bannerText} /> + ) : null} + {children} + <div className="mt-12"> + <h2 className="sr-only">{t("siteFooter")}</h2> + {!excludeFooterFeedback ? ( + <div className="layout-container mt-5"> + <Feedback /> + </div> + ) : ( + "" + )} + <div className="layout-container mb-2"> + <DateModified date={dateModifiedOverride} /> + </div> + </div> + + <Footer + id="footer" + lang={locale} + btnLink={"#"} + preFooterTitle={preFooterTitle} + preFooterLink={preFooterLink} + preFooterLinkText={preFooterLinkText} + /> + </div> + ); +}; + +Layout.propTypes = { + /** + * text for the banner + */ + bannerText: PropTypes.string, + + /** + * title of the banner + */ + bannerTitle: PropTypes.string, + + /** + * child elements that will constitute the page + */ + children: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.element, + PropTypes.arrayOf(PropTypes.element), + ]), + + /** + * currently active locale + */ + locale: PropTypes.string, + + /** + * URL to use for navigation when changing locales + */ + langUrl: PropTypes.string, + + /** + * Array of Items for the breadcrumb + */ + breadcrumbItems: PropTypes.arrayOf( + PropTypes.shape({ + /** + * Text for the breadcrumb + */ + text: PropTypes.string, + + /** + * Link for the breadcrumb + */ + link: PropTypes.string, + }) + ), + + /** + * For activating feedback on active projects pages + */ + feedbackActive: PropTypes.bool, + /** + * Boolean that determines whether the disclaimer at the top of the screen is shown or not + */ + showDisclaimer: PropTypes.bool, + /** + * Project/page name that feedback is coming from + */ + projectName: PropTypes.string, + /** + * Path that the feedback is coming from + */ + path: PropTypes.string, + /** + * Boolean that determines whether the footer feedback is shown or not + */ + excludeFooterFeedback: PropTypes.bool, + /** + * Title for the pre-footer + */ + preFooterTitle: PropTypes.string, + /** + * URL for the pre-footer link + */ + preFooterLink: PropTypes.string, + /** + * Text for the pre-footer link + */ + preFooterLinkText: PropTypes.string, + /** + * Manual override for date modified component + */ + dateModifiedOverride: PropTypes.string, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 | 1x +1x + +1x + + + + +1x + + + + + + + + + + + + + + + +6x +4x + +1x + + + + +1x + + + + + + | import React from "react";
+import { Layout } from "./Layout";
+
+export default {
+ title: "Components/Organisms/Layout",
+ component: Layout,
+};
+
+const sampleText = () => {
+ return (
+ <p data-testid="child-element">
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
+ veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
+ commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
+ velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
+ cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
+ est laborum.
+ </p>
+ );
+};
+
+const Template = (args) => <Layout {...args}>{sampleText()}</Layout>;
+
+export const NoBanner = Template.bind({});
+export const WithBanner = Template.bind({});
+
+NoBanner.args = {
+ langUrl: "someUrl",
+ locale: "someLocale",
+};
+
+WithBanner.args = {
+ bannerTitle: "Banner Title",
+ bannerText: "Banner Text",
+ langUrl: "someUrl",
+ locale: "someLocale",
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 | 9x +9x +9x + +9x +9x + + + + + +9x + + + + + + + +3x +3x +3x + +3x +1x + + +1x + + +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +9x + + + + + + + + + + + + + + + + + + + + + + +9x + | import React from "react"; +import PropTypes from "prop-types"; +import { useTranslation } from "next-i18next"; +import { useState, useRef } from "react"; +import { FeedbackWidget } from "../molecules/FeedbackWidget"; +import { ActionButton } from "../atoms/ActionButton"; + +/** + * Displays the PhaseBanner on the page + */ + +export const PhaseBanner = ({ + phase, + text, + feedbackActive, + projectName, + path, + toggleForm, +}) => { + const [showFeedback, setShowFeedback] = useState(false); + const { t } = useTranslation("common"); + const toggle = useRef("Collapsed"); + + toggleForm = async (e) => { + Iif (showFeedback) { + toggle.current = "Collapsed"; + } else { + toggle.current = "Expanded"; + } + + setShowFeedback(!showFeedback); + }; + + return ( + <> + <div className="bg-multi-blue-blue70d"> + <div className="block lg:flex py-4 layout-container"> + <div + className={`flex justify-between lg:block lg:w-max ${ + feedbackActive ? "mt-2" : "" + }`} + > + <span + className="font-body text-s text-white border-2 block w-max px-4 py-1 my-auto leading-6 items-center" + role="alert" + > + {phase} + </span> + {feedbackActive ? ( + <ActionButton + id="back-projects" + dataCy="back-projects" + dataTestId="back-projects" + custom="font-body w-max text-xs underline text-white block outline-none focus:outline-white-solid h-full flex items-center -mt-2 py-2" + text={t("backProjects")} + href={t("breadCrumbsHref2")} + /> + ) : ( + "" + )} + </div> + <div> + <p className="mt-2 lg:mt-0 h-full font-body text-xs lg:text-sm text-white lg:ml-4 my-auto flex items-center"> + {text} + </p> + </div> + </div> + {feedbackActive ? ( + <div className="py-4 outline-none bg-custom-blue-blue font-body text-xs lg:text-sm text-white flex items-center lg:my-0"> + <div className="flex layout-container"> + <span + className="invisible hidden md:block font-body text-xs text-white border block w-max px-4 py-1 my-auto leading-6 items-center" + role="alert" + > + {phase} + </span> + <div className="lg:ml-6 xl:ml-12 xxl:ml-14 my-auto"> + <button + id="feedbackButton" + onClick={toggleForm} + className="flex focus:outline-white-solid items-center lg:ml-4 my-auto" + data-testid="feedbackButton" + > + <strong className="underline"> + {t("giveFeedback")} + <span className="sr-only">{toggle.current}</span> + </strong> + <img + className="px-2 flex items-center" + src="/feedback-icon-white.svg" + alt="" + /> + </button> + </div> + </div> + </div> + ) : ( + "" + )} + </div> + + <FeedbackWidget + showFeedback={showFeedback} + toggleForm={toggleForm} + projectName={projectName} + path={path} + /> + </> + ); +}; + +PhaseBanner.propTypes = { + /** + * Phase stage in the PhaseBanner + */ + phase: PropTypes.string.isRequired, + /** + * Phasebanner text + */ + text: PropTypes.string.isRequired, + /** + * This is for showing the feedback component + */ + feedbackActive: PropTypes.bool, + /** + * Project/page name that feedback is coming from + */ + projectName: PropTypes.string, + /** + * Path that the feedback is coming from + */ + path: PropTypes.string, +}; + +export default PhaseBanner; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 | 1x +1x + +1x + + + + + + +2x +2x + +1x + + + + +1x + + + + + | import React from "react";
+import PhaseBanner from "./PhaseBanner";
+
+export default {
+ title: "Components/Atoms/PhaseBanner",
+ component: PhaseBanner,
+};
+
+const Template = (args) => <PhaseBanner {...args} />;
+
+export const Primary = Template.bind({});
+export const WithFeedback = Template.bind({});
+
+Primary.args = {
+ phase: "PhaseBanner Phase",
+ text: "PhaseBanner Text",
+};
+
+WithFeedback.args = {
+ phase: "PhaseBanner Phase",
+ text: "PhaseBanner Text",
+ feedbackActive: true,
+};
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 | 1x +1x +1x +1x +1x +1x +1x +1x +1x + + + + +7x +9x +8x + +8x + +8x + +3x + + +3x +3x +24x +21x +1x + + + + + +3x + +3x + + +3x +5x +5x + + + +3x +3x + + + +3x + + + + + + + + + + +3x + + + + + + + + + + +3x +21x + + + +3x + + + + + + + + + + + + +3x +1x + + +3x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1x + + + + + + | import PropTypes from "prop-types"; +import Link from "next/link"; +import { useState } from "react"; +import { useTranslation } from "next-i18next"; +import { OptionalTextField } from "../molecules/OptionalTextField"; +import { Details } from "../molecules/Details"; +import { ActionButton } from "../atoms/ActionButton"; +import { stripFeedback } from "../../lib/utils/stripFeedback"; +import { ErrorLabel } from "../atoms/ErrorLabel"; + +/** + * Report a problem button to report technical issues on the page. + */ +export function ReportAProblem(props) { + const [submitted, setSubmitted] = useState(false); + const { t, i18n } = useTranslation(); + + const [submittedOnce, setSubmittedOnce] = useState(false); + + let onSubmitHandler = (e) => { + //Checking if at least one checkbox is selected + let checkBoxSelected = false; + + //Check the checkboxes + let inputElements = document.getElementsByTagName("input"); + for (let index = 0; index < inputElements.length; index++) { + if (inputElements[index].type == "checkbox") { + if (inputElements[index].checked) { + checkBoxSelected = true; + } + } + } + + // prevent default behaviour of form + e.preventDefault(); + // create FormData object from form + const formData = new FormData(e.target); + + // Iterate through key/value pairs and strip personal identifier information from each value + for (var pair of formData.entries()) { + let cleanedFeedback = stripFeedback(pair[1]); + formData.set(pair[0], cleanedFeedback); + } + // create URLSearchParams object from FormData object + // this will be used to create url encoded string of names and values of the form fields + const urlEncoded = new URLSearchParams(formData); + let urlString = urlEncoded.toString(); + //Replace the values with yes for GCNotify + let values; + + Iif (formData.get("language").toString().localeCompare("fr") == 0) { + values = [ + "Informations+incorrectes", + "Informations+impr%C3%A9cises", + "Vous+n%E2%80%99avez+pas+trouv%C3%A9+ce+que+vous+cherchiez", + "La+page+ne+fonctionne+pas+avec+vos+technologies+d%E2%80%99adaptation", + "Vous+%C3%AAtes+inquiet+pour+votre+vie+priv%C3%A9e", + "Vous+ne+savez+pas+o%C3%B9+trouver+de+l%E2%80%99aide", + "Autres", + ]; + } else { + values = [ + "Incorrect+Information", + "Unclear+Information", + "You+didn%E2%80%99t+find+what+you+were+looking+for", + "Page+does+not+work+with+your+adaptive+technologies", + "You%E2%80%99re+worried+about+your+privacy", + "You+don%E2%80%99t+know+where+else+to+go+for+help", + "Other", + ]; + } + + for (const value of values) { + urlString = urlString.replace(value, "yes"); + } + + // call report a problem API route + fetch("/api/report-a-problem", { + method: "POST", + headers: { + "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8", + }, + body: urlString, + }).catch((e) => { + // handle error if fetch fails + // fetch only fails if there is no internet connection not for the actual + // request so there is nothing really to do here other than to log it + console.log(e); + }); + + if (checkBoxSelected) { + setSubmitted(true); + } + //Make sure the form was submitted at least once + setSubmittedOnce(true); + }; + + return ( + <Details + label={t("footerReportProblemButtonString", { lng: props.language })} + dataCy="report-a-problem-details" + dataTestId="report-a-problem-details" + > + <div role="status"> + {submitted ? ( + <> + <h2 className="text-h3 font-display mb-4 font-bold"> + <b> + {t("reportAProblemThankYouForYourHelp", { + lng: props.language, + })} + </b> + </h2> + <p className="text-sm font-body"> + {t("reportAProblemYouWillNotBeContacted", { + lng: props.language, + })} + </p> + </> + ) : ( + "" + )} + </div> + {submitted ? ( + "" + ) : ( + <> + <h2 className="text-base font-body mt-0"> + {t("reportAProblemTitle", { lng: props.language })} + </h2> + <ul className="list-outside list-disc px-6 py-2"> + <li className="text-xs sm:text-sm font-body mb-4 leading-tight sm:leading-6"> + <b>{t("reportAProblemNoReply", { lng: props.language })}</b> + </li> + <li className="text-xs sm:text-sm font-body my-4 leading-tight sm:leading-6"> + <b> + {t("reportAProblemFeedbackConfidential", { + lng: props.language, + })} + </b>{" "} + <Link + href="/signup/privacy" + className="underline text-xs sm:text-sm font-body hover:text-canada-footer-hover-font-blue text-canada-footer-font" + > + {t("reportAProblemPrivacyStatement", { lng: props.language })} + </Link> + </li> + </ul> + <form + data-gc-analytics-formname="ESDC|EDSC:ServiceCanadaLabsReport-Problem" + data-gc-analytics-collect='[{"value":"input,select","emptyField":"N/A"}]' + className="w-full" + action="#" + onSubmit={onSubmitHandler} + > + <input + type="hidden" + id="language" + name="language" + value={i18n.language} + /> + <fieldset> + <legend className="text-base sm:text-p font-body font-normal mb-6"> + <b className="text-error-border-red mr-2" aria-hidden="true"> + * + </b> + {t("reportAProblemCheckAllThatApply", { lng: props.language })} + </legend> + <OptionalTextField + controlId="incorrectInformationCheckBox" + textFieldId="incorrectInformationTextField" + controlName="incorrect_information" + textFieldName="incorrect_information_details" + controlLabel={t("reportAProblemIncorrectInformation", { + lng: props.language, + })} + textFieldLabel={t("reportAProblemProvideMoreDetails", { + lng: props.language, + })} + uncontrolled={true} + multiText={true} + textLabelBold={true} + wrap="hard" + maxLength={750} + controlDataTestId="incorrectInformation-checkbox" + textFieldDataTestId="incorrectInformation-text" + controlDataCy="incorrectInformation-checkbox" + textFieldDataCy="incorrectInformation-text" + describedby="incorrectInformation" + OptionalTextField + checkBoxStyle="mb-4 inline-block" + controlValue={t("reportAProblemIncorrectInformation", { + lng: props.language, + })} + /> + <OptionalTextField + controlId="unclearInformationCheckBox" + textFieldId="unclearInformationTextField" + controlName="unclear_information" + textFieldName="unclear_information_details" + controlLabel={t("reportAProblemUnclearInformation", { + lng: props.language, + })} + textFieldLabel={t("reportAProblemProvideMoreDetails", { + lng: props.language, + })} + uncontrolled={true} + multiText={true} + textLabelBold={true} + wrap="hard" + maxLength={750} + controlDataTestId="unclearInformation-checkbox" + textFieldDataTestId="unclearInformation-text" + controlDataCy="unclearInformation-checkbox" + textFieldDataCy="unclearInformation-text" + describedby="unclearInformation" + checkBoxStyle="mb-4 inline-block" + controlValue={t("reportAProblemUnclearInformation", { + lng: props.language, + })} + /> + <OptionalTextField + controlId="infoNotFoundCheckBox" + textFieldId="infoNotFoundTextField" + controlName="info_not_found" + textFieldName="info_not_found_details" + controlLabel={t("reportAProblemDidNotFindWhatYoureLookingFor", { + lng: props.language, + })} + textFieldLabel={t("reportAProblemProvideMoreDetails", { + lng: props.language, + })} + uncontrolled={true} + multiText={true} + textLabelBold={true} + wrap="hard" + maxLength={750} + controlDataTestId="infoNotFound-checkbox" + textFieldDataTestId="infoNotFound-text" + controlDataCy="infoNotFound-checkbox" + textFieldDataCy="infoNotFound-text" + describedby="infoNotFound" + checkBoxStyle="lg:mb-8 mb-4 inline-block" + controlValue={t("reportAProblemDidNotFindWhatYoureLookingFor", { + lng: props.language, + })} + /> + <OptionalTextField + controlId="adaptiveTechnologyCheckBox" + textFieldId="adaptiveTechnologyTextField" + controlName="adaptive_technology" + textFieldName="adaptive_technology_details" + controlLabel={t( + "reportAProblemPageDoesNotWorkWithAdaptiveTechnology", + { lng: props.language } + )} + textFieldLabel={t("reportAProblemProvideMoreDetails", { + lng: props.language, + })} + uncontrolled={true} + multiText={true} + textLabelBold={true} + wrap="hard" + maxLength={750} + controlDataTestId="adaptiveTechnology-checkbox" + textFieldDataTestId="adaptiveTechnology-text" + controlDataCy="adaptiveTechnology-checkbox" + textFieldDataCy="adaptiveTechnology-text" + describedby="adaptiveTechnology" + checkBoxStyle="mb-8 inline-block" + controlValue={t( + "reportAProblemPageDoesNotWorkWithAdaptiveTechnology", + { lng: props.language } + )} + /> + <OptionalTextField + controlId="privacyIssuesCheckBox" + textFieldId="privacyIssuesTextField" + controlName="privacy_issues" + textFieldName="privacy_issues_details" + controlLabel={t("reportAProblemYoureWorriedAboutYourPrivacy", { + lng: props.language, + })} + textFieldLabel={t("reportAProblemProvideMoreDetails", { + lng: props.language, + })} + uncontrolled={true} + multiText={true} + textLabelBold={true} + wrap="hard" + maxLength={750} + controlDataTestId="privacyIssues-checkbox" + textFieldDataTestId="privacyIssues-text" + controlDataCy="privacyIssues-checkbox" + textFieldDataCy="privacyIssues-text" + describedby="privacyIssues" + checkBoxStyle="mb-4 inline-block" + controlValue={t("reportAProblemYoureWorriedAboutYourPrivacy", { + lng: props.language, + })} + /> + <OptionalTextField + controlId="noWhereElseToGoCheckBox" + textFieldId="noWhereElseToGoTextField" + controlName="no_where_else_to_go" + textFieldName="no_where_else_to_go_details" + controlLabel={t("reportAProblemNoWhereElseToGo", { + lng: props.language, + })} + textFieldLabel={t("reportAProblemProvideMoreDetails", { + lng: props.language, + })} + uncontrolled={true} + multiText={true} + textLabelBold={true} + wrap="hard" + maxLength={750} + controlDataTestId="noWhereElseToGo-checkbox" + textFieldDataTestId="noWhereElseToGo-text" + controlDataCy="noWhereElseToGo-checkbox" + textFieldDataCy="noWhereElseToGo-text" + describedby="noWhereElseToGo" + checkBoxStyle="lg:mb-8 mb-4 inline-block" + controlValue={t("reportAProblemNoWhereElseToGo", { + lng: props.language, + })} + /> + <OptionalTextField + controlId="otherCheckBox" + textFieldId="otherTextField" + controlName="other" + textFieldName="other_details" + controlLabel={t("reportAProblemOther", { lng: props.language })} + textFieldLabel={t("reportAProblemProvideMoreDetails", { + lng: props.language, + })} + uncontrolled={true} + multiText={true} + textLabelBold={true} + wrap="hard" + maxLength={750} + controlDataTestId="other-checkbox" + textFieldDataTestId="other-text" + controlDataCy="other-checkbox" + textFieldDataCy="other-text" + describedby="other" + checkBoxStyle="mb-4" + controlValue={t("reportAProblemOther", { lng: props.language })} + /> + {submittedOnce ? ( + <ErrorLabel + message={t("reportAProblemError", { lng: props.language })} + /> + ) : undefined} + </fieldset> + <ActionButton + id="submit" + className="rounded block mt-4" + type="submit" + dataCy="report-a-problem-submit" + dataTestId="report-a-problem-submit" + analyticsTracking + > + {t("reportAProblemSubmit", { lng: props.language })} + </ActionButton> + </form> + </> + )} + </Details> + ); +} + +ReportAProblem.propTypes = { + /** + * Translation language + */ + language: PropTypes.string, +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 | 1x +1x + +1x + + + + + + +10x + | import React from "react";
+import { ReportAProblem } from "./ReportAProblem";
+
+export default {
+ title: "Components/Organisms/ReportAProblem",
+ component: ReportAProblem,
+};
+
+const Template = (args) => <ReportAProblem {...args} />;
+
+export const Primary = Template.bind({});
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +File | ++ | Statements | ++ | Branches | ++ | Functions | ++ | Lines | ++ |
---|---|---|---|---|---|---|---|---|---|
Feedback.js | +
+
+ |
+ 62.5% | +10/16 | +80% | +4/5 | +25% | +1/4 | +60% | +9/15 | +
Footer.js | +
+
+ |
+ 100% | +8/8 | +50% | +2/4 | +100% | +1/1 | +100% | +7/7 | +
Footer.stories.js | +
+
+ |
+ 85.71% | +6/7 | +100% | +0/0 | +100% | +0/0 | +100% | +5/5 | +
HelpIcon.js | +
+
+ |
+ 80% | +8/10 | +20% | +1/5 | +33.33% | +1/3 | +100% | +7/7 | +
HelpIcon.stories.js | +
+
+ |
+ 76.92% | +10/13 | +100% | +0/0 | +100% | +0/0 | +100% | +9/9 | +
Layout.js | +
+
+ |
+ 100% | +17/17 | +63.63% | +14/22 | +100% | +1/1 | +100% | +16/16 | +
Layout.stories.js | +
+
+ |
+ 90.9% | +10/11 | +100% | +0/0 | +100% | +1/1 | +100% | +8/8 | +
PhaseBanner.js | +
+
+ |
+ 88.88% | +16/18 | +87.5% | +7/8 | +100% | +2/2 | +93.75% | +15/16 | +
PhaseBanner.stories.js | +
+
+ |
+ 90% | +9/10 | +100% | +0/0 | +100% | +0/0 | +100% | +7/7 | +
ReportAProblem.js | +
+
+ |
+ 94.87% | +37/39 | +90% | +9/10 | +66.66% | +2/3 | +94.73% | +36/38 | +
ReportAProblem.stories.js | +
+
+ |
+ 83.33% | +5/6 | +100% | +0/0 | +100% | +0/0 | +100% | +4/4 | +
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 | 11x + +11x +11x +11x +11x +11x +11x +11x +11x +11x + + +11x + + + + + + + + + + + +99x +500x +499x + +499x + + + + + +1x + + + + + + + +400x + + + + + + + + + | import { v4 as uuid } from "uuid"; + +import Header from "./nodes/Header"; +import LineBreak from "./nodes/LineBreak"; +import ListItem from "./nodes/ListItem"; +import OrderedList from "./nodes/OrderedList"; +import Paragraph from "./nodes/Paragraph"; +import Text from "./nodes/Text"; +import Span from "./nodes/Span"; +import UnorderedList from "./nodes/UnorderedList"; +import Link from "./nodes/Link"; + +// todo: more components will like need to be added, but for now, these are the only ones returned in the aem json response +const NODES = { + header: Header, + paragraph: Paragraph, + link: Link, + text: Text, + span: Span, + "unordered-list": UnorderedList, + "ordered-list": OrderedList, + "list-item": ListItem, + "line-break": LineBreak, +}; + +export default function TextRecur(props) { + const Node = NODES[props.node?.nodeType]; + let content = props.node?.content; + + if ( + !Node || + (props.excludeH1 && + props.node?.nodeType === "header" && + props.node?.style === "h1") + ) { + return; + } + + return ( + <> + {content && content.length ? ( + <Node key={uuid()} node={props.node} index={props.index}> + {content.map((node) => ( + <TextRecur key={uuid()} node={node} /> + ))} + </Node> + ) : ( + <Node key={uuid()} node={props.node}></Node> + )} + </> + ); +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 | 11x +11x + +33x + + + +99x + + + + + + + + + + + + | import TextRecur from "./TextRecur"; +import { v4 as uuid } from "uuid"; + +export default function TextRender(props) { + return ( + <> + {props.data.map((node, index) => { + return ( + <TextRecur + key={uuid()} + node={node} + index={index} + excludeH1={props.excludeH1} + /> + ); + })} + </> + ); +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +File | ++ | Statements | ++ | Branches | ++ | Functions | ++ | Lines | ++ |
---|---|---|---|---|---|---|---|---|---|
TextRecur.jsx | +
+
+ |
+ 100% | +17/17 | +100% | +9/9 | +100% | +2/2 | +100% | +17/17 | +
TextRender.jsx | +
+
+ |
+ 100% | +4/4 | +100% | +0/0 | +100% | +2/2 | +100% | +4/4 | +
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 | 11x +18x + + + + + + + + + + + + + + + + + + + | export default function Header(props) { + switch (props.node.style) { + case "h1": + return ( + <h1 className={props.index === 0 ? "mt-0" : ""}>{props.children}</h1> + ); + case "h2": + return ( + <h2 className={props.index === 0 ? "mt-0" : ""}>{props.children}</h2> + ); + case "h3": + return <h3 className="mt-12">{props.children}</h3>; + case "h4": + return <h4>{props.children}</h4>; + case "h5": + return <h5>{props.children}</h5>; + default: + return <h6>{props.children}</h6>; + } +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 | 11x +22x + + | export default function LineBreak() { + return <br />; +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 | 11x + + + + + + + + + + | export default function Link(props) { + return ( + <a + href={props.node.data.href} + className="underline underline-offset-[6px] text-custom-blue-projects-link hover:text-custom-blue-projects-link-hover" + > + {props.node.value} + </a> + ); +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 | 11x + + + | export default function ListItem(props) { + return <li className="ml-10 text-[20px]">{props.children}</li>; +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 | 11x + + + | export default function UnorderedList(props) { + return <ol className="list-decimal">{props.children}</ol>; +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 | 11x + + + | export default function Paragraph(props) { + return <p>{props.children}</p>; +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 | 11x + + + | export default function Span(props) {
+ return <span>{props.children}</span>;
+}
+ |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 | 11x + +216x + + + + + + + + + | export default function Text(props) { + // todo: guessing on italic since I didn't see it, but I'm assuming it exists and will need to be updated + switch (props.node?.format?.variants?.[0]) { + case "strong": + return <strong>{props.node.value}</strong>; + case "emphasis": + return <em>{props.node.value}</em>; + default: + return <>{props.node.value}</>; + } +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 | 11x + + + | export default function UnorderedList(props) { + return <ul className="list-disc">{props.children}</ul>; +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +File | ++ | Statements | ++ | Branches | ++ | Functions | ++ | Lines | ++ |
---|---|---|---|---|---|---|---|---|---|
Header.jsx | +
+
+ |
+ 100% | +2/2 | +50% | +2/4 | +100% | +1/1 | +100% | +2/2 | +
LineBreak.jsx | +
+
+ |
+ 100% | +2/2 | +100% | +0/0 | +100% | +1/1 | +100% | +2/2 | +
Link.jsx | +
+
+ |
+ 100% | +1/1 | +100% | +0/0 | +100% | +1/1 | +100% | +1/1 | +
ListItem.jsx | +
+
+ |
+ 100% | +1/1 | +100% | +0/0 | +100% | +1/1 | +100% | +1/1 | +
OrderedList.jsx | +
+
+ |
+ 100% | +1/1 | +100% | +0/0 | +100% | +1/1 | +100% | +1/1 | +
Paragraph.jsx | +
+
+ |
+ 100% | +1/1 | +100% | +0/0 | +100% | +1/1 | +100% | +1/1 | +
Span.jsx | +
+
+ |
+ 100% | +1/1 | +100% | +0/0 | +0% | +0/1 | +100% | +1/1 | +
Text.jsx | +
+
+ |
+ 100% | +2/2 | +100% | +0/0 | +100% | +1/1 | +100% | +2/2 | +
UnorderedList.jsx | +
+
+ |
+ 100% | +1/1 | +100% | +0/0 | +100% | +1/1 | +100% | +1/1 | +
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +File | ++ | Statements | ++ | Branches | ++ | Functions | ++ | Lines | ++ |
---|---|---|---|---|---|---|---|---|---|
components | +
+
+ |
+ 0% | +0/1 | +100% | +0/0 | +100% | +0/0 | +0% | +0/1 | +
components/atoms | +
+
+ |
+ 92.26% | +334/362 | +71.96% | +154/214 | +91.89% | +34/37 | +98.63% | +289/293 | +
components/fragment_renderer | +
+
+ |
+ 89.28% | +50/56 | +39.78% | +37/93 | +75% | +3/4 | +89.58% | +43/48 | +
components/fragment_renderer/fragment_components | +
+
+ |
+ 85.57% | +89/104 | +42.1% | +8/19 | +88.88% | +8/9 | +92.77% | +77/83 | +
components/molecules | +
+
+ |
+ 86.25% | +345/400 | +57.69% | +90/156 | +75.51% | +37/49 | +90.85% | +308/339 | +
components/organisms | +
+
+ |
+ 87.74% | +136/155 | +68.51% | +37/54 | +60% | +9/15 | +93.18% | +123/132 | +
components/text_node_renderer | +
+
+ |
+ 100% | +21/21 | +100% | +9/9 | +100% | +4/4 | +100% | +21/21 | +
components/text_node_renderer/nodes | +
+
+ |
+ 100% | +12/12 | +50% | +2/4 | +88.88% | +8/9 | +100% | +12/12 | +
lib/notify | +
+
+ |
+ 72.72% | +8/11 | +100% | +0/0 | +33.33% | +1/3 | +66.66% | +6/9 | +
lib/utils | +
+
+ |
+ 56% | +28/50 | +45% | +9/20 | +54.54% | +6/11 | +55.55% | +25/45 | +
middlewares | +
+
+ |
+ 57.89% | +11/19 | +25% | +1/4 | +42.85% | +3/7 | +57.89% | +11/19 | +
pages | +
+
+ |
+ 51.66% | +93/180 | +31.85% | +72/226 | +46.42% | +13/28 | +54.11% | +92/170 | +
pages/api | +
+
+ |
+ 90.24% | +37/41 | +87.5% | +14/16 | +75% | +3/4 | +90% | +36/40 | +
pages/projects/benefits-finder | +
+
+ |
+ 37.7% | +23/61 | +37.03% | +40/108 | +36.36% | +4/11 | +39.65% | +23/58 | +
pages/projects/benefits-navigator | +
+
+ |
+ 39.68% | +25/63 | +41.02% | +64/156 | +36.36% | +4/11 | +41.66% | +25/60 | +
pages/projects/dashboard | +
+
+ |
+ 40.62% | +26/64 | +37.96% | +41/108 | +36.36% | +4/11 | +42.62% | +26/61 | +
pages/projects/digital-standards-playbook | +
+
+ |
+ 36.5% | +23/63 | +41.54% | +59/142 | +36.36% | +4/11 | +38.33% | +23/60 | +
pages/projects/making-easier-get-benefits | +
+
+ |
+ 35.93% | +23/64 | +32.14% | +36/112 | +27.27% | +3/11 | +37.7% | +23/61 | +
pages/projects/oas-benefits-estimator | +
+
+ |
+ 36.5% | +23/63 | +39.23% | +51/130 | +36.36% | +4/11 | +38.33% | +23/60 | +
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +File | ++ | Statements | ++ | Branches | ++ | Functions | ++ | Lines | ++ |
---|---|---|---|---|---|---|---|---|---|
postFeedbackToGcNotify.js | +
+
+ |
+ 50% | +1/2 | +100% | +0/0 | +0% | +0/1 | +50% | +1/2 | +
submitEmail.js | +
+
+ |
+ 77.77% | +7/9 | +100% | +0/0 | +50% | +1/2 | +71.42% | +5/7 | +
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 | 1x + + + + + + + + + + + + + + + + + + + | export async function postFeedbackToGcNotify(data) { + return await fetch( + `${process.env.NOTIFY_BASE_API_URL}/v2/notifications/email`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `ApiKey-v1 ${process.env.NOTIFY_API_KEY}`, + }, + body: JSON.stringify({ + email_address: process.env.SUBMIT_FEEDBACK_EMAIL, + template_id: process.env.NOTIFY_FEEDBACK_TEMPLATE_ID, + personalisation: { + ...data, + }, + }), + } + ); +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 | 2x + +2x + + + + + + + +1x + + + + + + + + + + + + + + + + + +1x + + +2x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import "node-fetch"; + +export const submitEmail = async ( + data, + defaults, + templateId, + email, + notifyApiAddress, + notifyApiKey +) => { + const notifyResponse = await fetch(notifyApiAddress, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `ApiKey-v1 ${notifyApiKey}`, + }, + body: JSON.stringify({ + email_address: email, + template_id: templateId, + // notify requires all values in the template to be present + // in the request.... highly annoying but providing defaults solves this + personalisation: { + ...defaults, + ...data, + }, + }), + }); + + return [notifyResponse.status, await notifyResponse.json()]; +}; + +export const submitEmailWithAttachment = async ( + data, + defaults, + templateId, + email, + file, + fileName, + notifyApiAddress, + notifyApiKey +) => { + const notifyResponse = await fetch(notifyApiAddress, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `ApiKey-v1 ${notifyApiKey}`, + }, + body: JSON.stringify({ + email_address: email, + template_id: templateId, + // notify requires all values in the template to be present + // in the request.... highly annoying but providing defaults solves this + personalisation: { + application_file: { + file: file, + filename: fileName, + sending_method: "attach", + }, + ...defaults, + ...data, + }, + }), + }); + return [notifyResponse.status, await notifyResponse.json()]; +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 | 6x +6x +6x + + + + + + + + + + | export const createBreadcrumbs = (breadcrumbArray, locale) => { + return breadcrumbArray.map((breadCrumbItem) => { + return { + text: + locale === "en" ? breadCrumbItem.scTitleEn : breadCrumbItem.scTitleFr, + link: + locale === "en" + ? breadCrumbItem.scPageNameEn + : breadCrumbItem.scPageNameFr, + }; + }); +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | export const generateCollapseElements = (json) => { + const elements = []; + + for (const item of json) { + if (item.nodeType === "paragraph") { + elements.push( + <p key={elements.length}>{generateCollapseElements(item.content)}</p> + ); + } else if (item.nodeType === "unordered-list") { + const listItems = item.content.map((listItem, index) => ( + <li key={index} className="my-0"> + {generateCollapseElements(listItem.content)} + </li> + )); + elements.push( + <ul key={elements.length} className="mb-0"> + {listItems} + </ul> + ); + } else if (item.nodeType === "ordered-list") { + const listItems = item.content.map((listItem, index) => ( + <li key={index} className="my-0"> + {generateCollapseElements(listItem.content)} + </li> + )); + elements.push( + <ol key={elements.length} className="mb-0"> + {listItems} + </ol> + ); + } else if (item.nodeType === "list-item") { + elements.push( + <li key={elements.length} className="my-0"> + {generateCollapseElements(item.content)} + </li> + ); + } else Iif (item.nodeType === "text") { + elements.push(item.value); + } + } + + return elements; +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 | + + + + + + + + + + + + + + + + | export function getAllUpdateIds(items) { + return items.flatMap((item) => [ + { + params: { + id: item.scPageNameEn, + }, + locale: "en", + }, + { + params: { + id: item.scPageNameFr, + }, + locale: "fr", + }, + ]); +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +File | ++ | Statements | ++ | Branches | ++ | Functions | ++ | Lines | ++ |
---|---|---|---|---|---|---|---|---|---|
createBreadcrumbs.js | +
+
+ |
+ 100% | +4/4 | +50% | +2/4 | +100% | +2/2 | +100% | +3/3 | +
generateCollapseElements.js | +
+
+ |
+ 0% | +0/19 | +0% | +0/9 | +0% | +0/3 | +0% | +0/18 | +
getAllUpdateIds.js | +
+
+ |
+ 0% | +0/3 | +100% | +0/0 | +0% | +0/2 | +0% | +0/2 | +
maskEmail.js | +
+
+ |
+ 100% | +13/13 | +100% | +7/7 | +100% | +1/1 | +100% | +12/12 | +
sortUpdatesByDate.js | +
+
+ |
+ 100% | +4/4 | +100% | +0/0 | +100% | +2/2 | +100% | +3/3 | +
stripFeedback.js | +
+
+ |
+ 100% | +7/7 | +100% | +0/0 | +100% | +1/1 | +100% | +7/7 | +
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 | +1x +1x +1x + +1x +14x +1x +13x +10x +10x + +3x +3x + + + +1x + + | //Function for masking email to get in the thank you page later +export function maskEmail(email) { + let maskedEmail = ""; + let x = 0; + + for (var i = 0; i < email.length; i++) { + if (i === 0) { + maskedEmail += email[i]; + } else if (email[i] !== "@" && email[i] !== "." && x <= 3) { + maskedEmail += "*"; + x += 1; + } else { + maskedEmail += email[i]; + x = 0; + } + } + + return maskedEmail; +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 | 6x +6x +3x + + + | export const sortUpdatesByDate = (array) => { + return [...array].sort((a, b) => { + return b.scDateModifiedOverwrite.localeCompare(a.scDateModifiedOverwrite); + }); +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 | 7x + +7x + + + + + +7x + + + + + +7x + + + + + +7x + + + +7x + + + + +7x + + | export function stripFeedback(feedbackToClean) { + //Remove postal code from feedback + feedbackToClean = feedbackToClean.replaceAll( + /[ABCEGHJ-NPRSTVXY]\d[ABCEGHJ-NPRSTV-Z][ -]?\d[ABCEGHJ-NPRSTV-Z]\d/gim, + "### ###" + ); + + //Remove SIN from feedback + feedbackToClean = feedbackToClean.replaceAll( + /(\d{3}\s*\d{3}\s*\d{3}|\d{3}\D*\d{3}\D*\d{3})/gm, + "### ### ###" + ); + + //Remove email from feedback + feedbackToClean = feedbackToClean.replaceAll( + /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*/gim, + "####@####.####" + ); + + //Removes phone number from feedback + feedbackToClean = feedbackToClean.replaceAll( + /(\+\d{1,2}\s?)?1?\-?\.?\s?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}/gm, + "# ### ### ###" + ); + feedbackToClean = feedbackToClean.replaceAll( + /(?:(?:\+?1\s*(?:[.-]\s*)?)?(?:\(\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\s*\)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\s*(?:[.-]\s*)?)?([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\s*(?:[.-]\s*)?([0-9]{4})(?:\s*(?:#|x\.?|ext\.?|extension)\s*(\d+))?/gm, + "# ### ### ###" + ); + + return feedbackToClean; +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +File | ++ | Statements | ++ | Branches | ++ | Functions | ++ | Lines | ++ |
---|---|---|---|---|---|---|---|---|---|
initMiddleware.js | +
+
+ |
+ 0% | +0/7 | +0% | +0/1 | +0% | +0/4 | +0% | +0/7 | +
joi.js | +
+
+ |
+ 91.66% | +11/12 | +33.33% | +1/3 | +100% | +3/3 | +91.66% | +11/12 | +
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 | + + + + + + + + + + + + + | // Helper method to wait for a middleware to execute before continuing +// And to throw an error when an error happens in a middleware +export default function initMiddleware(middleware) { + return (req, res) => + new Promise((resolve, reject) => { + middleware(req, res, (result) => { + Iif (result instanceof Error) { + return reject(result); + } + return resolve(result); + }); + }); +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 | 1x +1x + + + + + + + + +1x +1x +1x +1x +1x + + +1x +1x +2x + +1x + + + + | import { Schema, ValidationOptions } from "joi"; //lgtm [js/unused-local-variable] +import { NextApiHandler } from "next"; //lgtm [js/unused-local-variable] + +/** + * middleware to validate body of request with Joi schema + * if valid handler will be called otherwise a 400 response with the errors will be returned + * @param schema {Schema} - joi validation schema + * @param handler {NextApiHandler} - the next handler to call if the schema is valid + * @param options {ValidationOptions} - the Joi validations options + */ +export default function validate(schema, handler, options = {}) { + return async (req, res) => { + const { error } = await schema.validate(req.body, options); + const valid = error === undefined; + Iif (valid) { + return handler(req, res); + } else { + const { details } = error; + const message = details.map((i) => { + return { path: i.path, message: i.message }; + }); + res.status(400).json({ error: message }); + } + }; +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 | 1x +1x +1x +1x +1x +1x +1x +1x + +1x +2x +2x +2x +2x + +2x +1x + + + + + +1x + + +1x + + + + +2x +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + | import Head from "next/head"; +import { useTranslation } from "next-i18next"; +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; +import Link from "next/link"; +import { ActionButton } from "../components/atoms/ActionButton"; +import { useEffect, useState } from "react"; +import { useRouter } from "next/router"; +import aemServiceInstance from "../services/aemServiceInstance"; + +export default function error404(props) { + const { t } = useTranslation("common"); + const [loaded, setLoaded] = useState(false); + const router = useRouter(); + const [pageData] = useState(props.pageData.item); + + useEffect(() => { + Iif (props.adobeAnalyticsUrl) { + window.adobeDataLayer = window.adobeDataLayer || []; + window.adobeDataLayer.push({ event: "pageLoad" }); + } + + //If using Internet Explorer, redirect to /notsupported + Iif (window.document.documentMode) { + router.push("/notsupported"); + } else { + setLoaded(true); + } + }, []); + + //If using Internet Explorer, render empty page so page doesn't flash before redirect + if (!loaded) { + return <div></div>; + } + + return ( + <> + <Head> + {/* Primary HTML Meta Tags */} + <title data-gc-analytics-error="404"> + {pageData.scContentEn.json[0].content[0].value} (404) |{" "} + {pageData.scContentFr.json[0].content[0].value} (404) + </title> + <meta name="description" content={`${t("404errorMetaDescription")}`} /> + <meta name="author" content="Service Canada" /> + <link rel="icon" href="/favicon.ico" /> + <link rel="schema.dcterms" href="http://purl.org/dc/terms/" /> + + {/* DCMI Meta Tags */} + <meta name="dcterms.title" content={`404 — ${t("siteTitle")}`} /> + <meta + name="dcterms.language" + content={props.locale === "en" ? "eng" : "fra"} + title="ISO639-2/T" + /> + <meta + name="dcterms.description" + content={`${t("404errorMetaDescription")}`} + /> + <meta + name="dcterms.subject" + title="gccore" + content={t("metaSubject")} + /> + <meta + name="dcterms.creator" + content={ + props.locale === "en" + ? "Employment and Social Development Canada" + : "Emploi et Développement social Canada" + } + /> + <meta name="dcterms.accessRights" content="2" /> + <meta name="dcterms.service" content="ESDC-EDSC_SCLabs-LaboratoireSC" /> + <meta name="dcterms.issued" title="W3CDTF" content="2021-06-01" /> + <meta name="dcterms.modified" title="W3CDTF" content="2021-12-16" /> + <meta name="dcterms.spatial" content="Canada" /> + + {/* Open Graph / Facebook */} + <meta property="og:type" content="website" /> + <meta property="og:locale" content={props.locale} /> + <meta + property="og:url" + content={ + "https://alpha.service.canada.ca/" + `${props.locale}` + "/404" + } + /> + <meta property="og:title" content={`404 — ${t("siteTitle")}`} /> + <meta + property="og:description" + content={`${t("404errorMetaDescription")}`} + /> + <meta property="og:image" content={`${t("metaImage")}`} /> + <meta property="og:image:alt" content={`${t("siteTitle")}`} /> + + {/* Twitter */} + <meta property="twitter:card" content="summary_large_image" /> + <meta + property="twitter:url" + content={ + "https://alpha.service.canada.ca/" + `${props.locale}` + "/404" + } + /> + <meta property="twitter:title" content={`500 — ${t("siteTitle")}`} /> + <meta name="twitter:creator" content="Service Canada" /> + <meta + property="twitter:description" + content={`${t("404errorMetaDescription")}`} + /> + <meta property="twitter:image" content={`${t("metaImage")}`} /> + <meta property="twitter:image:alt" content={`${t("siteTitle")}`} /> + </Head> + <div className="min-h-screen relative"> + <section className="layout-container pb-44"> + <div className="pt-6"> + <img + src={`https://www.canada.ca${ + props.locale === "en" + ? pageData.scGcImages[0].scImageEn._path + : pageData.scGcImages[0].scImageFr._path + }`} + alt={ + props.locale === "en" + ? pageData.scGcImages[0].scImageAltTextEn + : pageData.scGcImages[0].scImageAltTextFr + } + width={575} + height={59} + /> + </div> + <div className="flex flex-col lg:flex-row justify-between items-center lg:items-start mt-8"> + <div> + <div className="relative h-auto xl:w-96 xxl:w-400px lg:w-72 xl:h-400px lg:h-500px mb-8 lg:mb-0"> + <h1 className="font-bold font-display mb-4"> + {pageData.scContentEn.json[0].content[0].value} + </h1> + <p className="font-bold font-body mb-8"> + {pageData.scContentEn.json[1].content[0].value} + </p> + <p className="font-body text-sm mb-4 leading-30px"> + {pageData.scContentEn.json[2].content[0].value} + </p> + <div className="flex"> + <span className="error404-link" /> + <p className="font-body text-sm leading-30px"> + {pageData.scContentEn.json[3].content[0].value} + <Link + href="/en/home" + locale={false} + className="underline hover:text-canada-footer-hover-font-blue text-canada-footer-font" + > + {pageData.scContentEn.json[3].content[1].value} + </Link> + </p> + </div> + </div> + </div> + <div className="flex items-center justify-center circle-background my-8 mx-4 lg:mt-0 lightbulb-bg shrink-0"> + <span className="relative lightbulb"> + <img + src={`https://www.canada.ca${ + props.locale === "en" + ? pageData.scImageList[0].scImageEn._path + : pageData.scImageList[0].scImageFr._path + }`} + alt="" + /> + </span> + </div> + <div> + <div + className="relative h-auto xl:w-96 xxl:w-400px lg:w-72 xl:h-400px lg:h-500px mb-8 lg:mb-0" + lang="fr" + > + <h1 className="font-bold font-display mb-4"> + {pageData.scContentFr.json[0].content[0].value} + </h1> + <p className="font-bold font-body mb-8"> + {pageData.scContentFr.json[1].content[0].value} + </p> + <p className="font-body text-sm mb-4 leading-30px"> + {pageData.scContentFr.json[2].content[0].value} + </p> + <div className="flex"> + <span className="error404-link" /> + <p className="font-body text-sm leading-30px"> + {pageData.scContentFr.json[3].content[0].value} + <Link + href="/fr/accueil" + locale={false} + className="underline hover:text-canada-footer-hover-font-blue text-canada-footer-font" + > + {pageData.scContentFr.json[3].content[1].value} + </Link> + </p> + </div> + </div> + </div> + </div> + </section> + <footer className="h-100px w-screen bg-footer-background-color absolute bottom-0"> + <div className="layout-container flex justify-between lg:flex-row-reverse pt-4 lg:pt-0 lg:mt-8"> + <ActionButton + id="404TopOfPageButton" + href="#" + custom="text-left w-32 flex flex-col lg:hidden" + text="Top of page / Haut de la page" + icon="icon-up-caret" + iconEnd + /> + <span className="relative footer-logo"> + <img + src={`https://www.canada.ca${ + props.locale === "en" + ? pageData.scGcImages[1].scImageEn._path + : pageData.scGcImages[1].scImageFr._path + }`} + alt={ + props.locale === "en" + ? pageData.scGcImages[1].scImageAltTextEn + : pageData.scGcImages[1].scImageAltTextFr + } + /> + </span> + </div> + </footer> + </div> + </> + ); +} + +export const getStaticProps = async ({ locale }) => { + const { data } = await aemServiceInstance.getFragment("error404Query"); + + return { + props: { + locale: locale, + adobeAnalyticsUrl: process.env.ADOBE_ANALYTICS_URL ?? null, + ...(await serverSideTranslations("en", ["common"])), + ...(await serverSideTranslations("fr", ["common"])), + pageData: data.sclabsErrorpageV1ByPath, + }, + }; +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 | 1x +1x +1x +1x +1x +1x +1x +1x + +1x +2x +2x +2x +2x + +2x +1x + + + + + +1x + + +1x + + + + +2x +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + | import Head from "next/head"; +import { useTranslation } from "next-i18next"; +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; +import Link from "next/link"; +import { ActionButton } from "../components/atoms/ActionButton"; +import { useEffect, useState } from "react"; +import { useRouter } from "next/router"; +import aemServiceInstance from "../services/aemServiceInstance"; + +export default function error500(props) { + const { t } = useTranslation("common"); + const [loaded, setLoaded] = useState(false); + const router = useRouter(); + const [pageData] = useState(props.pageData.item); + + useEffect(() => { + Iif (props.adobeAnalyticsUrl) { + window.adobeDataLayer = window.adobeDataLayer || []; + window.adobeDataLayer.push({ event: "pageLoad" }); + } + + //If using Internet Explorer, redirect to /notsupported + Iif (window.document.documentMode) { + router.push("/notsupported"); + } else { + setLoaded(true); + } + }, []); + + //If using Internet Explorer, render empty page so page doesn't flash before redirect + if (!loaded) { + return <div></div>; + } + + return ( + <> + <Head> + {/* Primary HTML Meta Tags */} + <title data-gc-analytics-error="500"> + {pageData.scContentEn.json[0].content[0].value} (500) |{" "} + {pageData.scContentFr.json[0].content[0].value} (500) + </title> + <meta + name="description" + content="Error message stating that the server is down, or the URL is incorrect or expired" + /> + <meta name="author" content="Service Canada" /> + <link rel="icon" href="/favicon.ico" /> + <link rel="schema.dcterms" href="http://purl.org/dc/terms/" /> + <meta content="width=device-width, initial-scale=1" name="viewport" /> + <meta name="robots" content="noindex, nofollow" /> + + {/* DCMI Meta Tags */} + <meta + property="dcterms:title" + lang="en" + content="The web site has reported an error (500)" + /> + <meta + property="dcterms:title" + lang="fr" + content="Le site Web a signalé une erreur (500)" + /> + <meta + name="dcterms.language" + content={props.locale === "en" ? "eng" : "fra"} + title="ISO639-2" + /> + <meta + property="dcterms:description" + lang="en" + content="Error message stating that the server is down, or the URL is incorrect or expired." + /> + <meta + property="dcterms:description" + lang="fr" + content="Message d’erreur indiquant que le serveur est en panne ou l’URL est incorrecte ou expirée." + /> + <meta property="dcterms:creator" lang="en" content="Service Canada" /> + <meta property="dcterms:creator" lang="fr" content="Service Canada" /> + <meta + property="dcterms:subject" + lang="en" + title="gccore" + content="GV Government and Politics;Government services" + /> + <meta + property="dcterms:subject" + lang="fr" + title="gccore" + content="GV Gouvernement et vie politique;Services gouvernementaux" + /> + <meta name="dcterms.accessRights" content="2" /> + <meta name="dcterms.service" content="ESDC-EDSC_SCLabs-LaboratoireSC" /> + <meta name="dcterms.issued" title="W3CDTF" content="2021-06-22" /> + <meta name="dcterms.modified" title="W3CDTF" content="2021-12-16" /> + <meta property="dcterms:issued" content="2021-06-22" /> + <meta property="dcterms:modified" content="2021-MM-DD" /> + + {/* Open Graph / Facebook */} + <meta property="og:type" content="website" /> + <meta property="og:locale" content={props.locale} /> + <meta + property="og:url" + content={ + "https://alpha.service.canada.ca/" + `${props.locale}` + "/500" + } + /> + <meta + property="og:title" + content="The web site has reported an error (500) | Le site Web a signalé une + erreur (500)" + /> + <meta + property="og:description" + content="Error message stating that the server is down, or the URL is incorrect or expired" + /> + <meta property="og:image" content={`${t("metaImage")}`} /> + <meta property="og:image:alt" content={`${t("siteTitle")}`} /> + + {/* Twitter */} + <meta property="twitter:card" content="summary_large_image" /> + <meta + property="twitter:url" + content={ + "https://alpha.service.canada.ca/" + `${props.locale}` + "/500" + } + /> + <meta + property="twitter:title" + content="Error message stating that the server is down, or the URL is incorrect or expired" + /> + <meta name="twitter:creator" content="Service Canada" /> + <meta + property="twitter:description" + content="Error message stating that the server is down, or the URL is incorrect or expired" + /> + <meta property="twitter:image" content={`${t("metaImage")}`} /> + <meta property="twitter:image:alt" content={`${t("siteTitle")}`} /> + </Head> + <div className="min-h-screen relative"> + <section className="layout-container pb-44"> + <div className="pt-6"> + <img + src={`https://www.canada.ca${ + props.locale === "en" + ? pageData.scGcImages[0].scImageEn._path + : pageData.scGcImages[0].scImageFr._path + }`} + alt={ + props.locale === "en" + ? pageData.scGcImages[0].scImageAltTextEn + : pageData.scGcImages[0].scImageAltTextFr + } + width={575} + height={59} + /> + </div> + <div className="flex flex-col lg:flex-row justify-between items-center lg:items-start mt-8"> + <div> + <div className="relative h-auto xl:w-96 xxl:w-400px lg:w-72 xl:h-400px lg:h-500px mb-8 lg:mb-0"> + <h1 className="font-bold font-display mb-4"> + {pageData.scContentEn.json[0].content[0].value} + </h1> + <p className="font-bold font-body mb-8"> + {pageData.scContentEn.json[1].content[0].value} + </p> + <p className="font-body text-sm mb-4 leading-30px"> + {pageData.scContentEn.json[2].content[0].value} + </p> + <div className="flex"> + <span className="error404-link" /> + <p className="font-body text-sm leading-30px"> + {pageData.scContentEn.json[3].content[0].value} + <Link + href="/en/home" + locale={false} + className="underline hover:text-canada-footer-hover-font-blue text-canada-footer-font" + > + {pageData.scContentEn.json[3].content[1].value} + </Link> + </p> + </div> + </div> + </div> + <div className="flex items-center justify-center circle-background my-8 lg:mt-0 lightbulb-bg"> + <span className="relative lightbulb"> + <img + src={`https://www.canada.ca${ + props.locale === "en" + ? pageData.scImageList[0].scImageEn._path + : pageData.scImageList[0].scImageFr._path + }`} + alt="" + /> + </span> + </div> + <div> + <div + className="relative h-auto xl:w-96 xxl:w-400px lg:w-72 xl:h-400px lg:h-500px mb-8 lg:mb-0" + lang="fr" + > + <h1 className="font-bold font-display mb-4"> + {pageData.scContentFr.json[0].content[0].value} + </h1> + <p className="font-bold font-body mb-8"> + {pageData.scContentFr.json[1].content[0].value} + </p> + <p className="font-body text-sm mb-4 leading-30px"> + {pageData.scContentFr.json[2].content[0].value} + </p> + <div className="flex"> + <span className="error50-link" /> + <p className="font-body text-sm leading-30px"> + {pageData.scContentFr.json[3].content[0].value} + <Link + href="/fr/accueil" + locale={false} + className="underline hover:text-canada-footer-hover-font-blue text-canada-footer-font" + > + {pageData.scContentFr.json[3].content[1].value} + </Link> + </p> + </div> + </div> + </div> + </div> + </section> + <footer className="h-100px w-screen bg-footer-background-color absolute bottom-0"> + <div className="layout-container flex justify-between lg:flex-row-reverse pt-4 lg:pt-0 lg:mt-8"> + <ActionButton + id="404TopOfPageButton" + href="#" + custom="text-left w-32 flex flex-col lg:hidden" + text="Top of page / Haut de la page" + icon="icon-up-caret" + iconEnd + /> + <span className="relative footer-logo"> + <img + src={`https://www.canada.ca${ + props.locale === "en" + ? pageData.scGcImages[1].scImageEn._path + : pageData.scGcImages[1].scImageFr._path + }`} + alt={ + props.locale === "en" + ? pageData.scGcImages[1].scImageAltTextEn + : pageData.scGcImages[1].scImageAltTextFr + } + /> + </span> + </div> + </footer> + </div> + </> + ); +} + +export const getStaticProps = async ({ locale }) => { + const { data } = await aemServiceInstance.getFragment("error500Query"); + + return { + props: { + locale: locale, + adobeAnalyticsUrl: process.env.ADOBE_ANALYTICS_URL ?? null, + ...(await serverSideTranslations("en", ["common"])), + ...(await serverSideTranslations("fr", ["common"])), + pageData: data.sclabsErrorpageV1ByPath, + }, + }; +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import { appWithTranslation } from "next-i18next"; +import "../styles/globals.css"; +import "../styles/forms.css"; +import "../styles/menu.css"; +import Head from "next/head"; +import { config } from "@fortawesome/fontawesome-svg-core"; +import "@fortawesome/fontawesome-svg-core/styles.css"; +import { Noto_Sans, Lato } from "next/font/google"; + +config.autoAddCss = false; + +const notoSans = Noto_Sans({ + subsets: ["latin"], + weight: ["300", "400", "700", "900"], + variable: "--font-notoSans", +}); +const lato = Lato({ + subsets: ["latin"], + weight: ["300", "400", "700", "900"], + variable: "--font-lato", +}); + +function MyApp({ Component, pageProps }) { + return ( + <> + <main className={`${notoSans.variable} ${lato.variable}`}> + <Component {...pageProps} /> + </main> + </> + ); +} + +export default appWithTranslation(MyApp); + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 | + + + + | // TODO: add checks for the status of the CMS +export default function handler(req, res) { + res.status(200).json({ message: "Status OK" }); +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +File | ++ | Statements | ++ | Branches | ++ | Functions | ++ | Lines | ++ |
---|---|---|---|---|---|---|---|---|---|
healthcheck.js | +
+
+ |
+ 0% | +0/2 | +100% | +0/0 | +0% | +0/1 | +0% | +0/2 | +
report-a-problem.js | +
+
+ |
+ 87.5% | +14/16 | +80% | +8/10 | +100% | +1/1 | +86.66% | +13/15 | +
robots.js | +
+
+ |
+ 100% | +11/11 | +100% | +2/2 | +100% | +1/1 | +100% | +11/11 | +
submit-feedback.js | +
+
+ |
+ 100% | +12/12 | +100% | +4/4 | +100% | +1/1 | +100% | +12/12 | +
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 | 1x + + + + + + +5x + +5x + + + +2x + +3x +3x + + + + + + + + + + + + + + + + + + + + + + + + + + + + +2x +1x + +1x +1x + + +1x +1x + + + + + + + + +5x + | import { submitEmail } from "../../lib/notify/submitEmail"; + +/** + * API handler for report a problem functionality. This will take form submissions + * and call GC Notify service with the appropriate template and data + */ +async function handler(req, res) { + if (req.method === "POST") { + // if there is no data specified we don't want to call notify + if ( + Object.keys(req.body).length <= 1 || + !process.env.REPORT_A_PROBLEM_ENABLED + ) { + res.status(200).end("OK"); + } else { + try { + const notifyResponse = await submitEmail( + { + ...req.body, + page_name: req.headers.referer || "unknown", + }, + { + page_name: "unknown", + language: "unknown", + incorrect_information: "no", + incorrect_information_details: "", + unclear_information: "no", + unclear_information_details: "", + info_not_found: "no", + info_not_found_details: "", + adaptive_technology: "no", + adaptive_technology_details: "", + privacy_issues: "no", + privacy_issues_details: "", + no_where_else_to_go: "no", + no_where_else_to_go_details: "", + other: "no", + other_details: "", + }, + process.env.NOTIFY_REPORT_A_PROBLEM_TEMPLATE_ID, + process.env.NEXT_PUBLIC_NOTIFY_REPORT_A_PROBLEM_EMAIL, + process.env.NOTIFY_BASE_API_URL + "/v2/notifications/email", + process.env.NOTIFY_API_KEY + ); + + if (notifyResponse[0] === 201) { + res.status(200).end("OK"); + } else { + console.error(notifyResponse[1]); + res.status(500).end("ERROR"); + } + } catch (e) { + console.error(e); + res.status(500).end("ERROR"); + } + } + } else E{ + res.setHeader("Allow", ["POST"]); + res.status(405).end(`Method ${req.method} Not Allowed`); + } +} + +export default handler; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 | + + + + + +2x +2x +1x +1x +1x +1x +1x +1x + +1x +1x + +2x + + | /** + * Disallow web crawlers to scrape our dev site, while only blocking crawlers from scraping the api routes in production + * @param req + * @param res + * @returns {Promise<void>} + */ +export default async function handler(req, res) { + if (process.env.NODE_ENV === "production") { + res.write("User-agent: *\n"); + res.write("Disallow: /api\n"); + res.write("Disallow: /projects/*\n"); + res.write("Disallow: /notsupported.js\n"); + res.write("Disallow: /cdcp-apply\n"); + res.write("Disallow: /rsdc-demander\n"); + } else { + res.write("User-agent: *\n"); + res.write("Disallow: /\n"); + } + res.end(); +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 | 1x + +3x +3x +3x +1x + +2x +2x +2x +1x + +1x + + +1x +1x + + + + | import { postFeedbackToGcNotify } from "../../lib/notify/postFeedbackToGcNotify"; + +export default async function handler(req, res) { + const data = req.body; + if (!data["what-was-wrong"]) { + res.status(400).json({ message: "required field missing" }); + } else { + try { + let r = await postFeedbackToGcNotify(data); + if (r.ok) { + res.status(200).json(data); + } else { + throw new Error("bad request"); + } + } catch (e) { + console.error("Failed to post to GC Notify"); + res.status(500).json({ message: "something went wrong" }); + } + } +} + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import Head from "next/head"; +import { useTranslation } from "next-i18next"; +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; +import { Layout } from "../components/organisms/Layout"; +import { ActionButton } from "../components/atoms/ActionButton"; +import { createBreadcrumbs } from "../lib/utils/createBreadcrumbs"; +import { useEffect } from "react"; + +export default function CDCPLanding(props) { + const { t } = useTranslation("common"); + + const breadCrumbs = [ + { + scTitleEn: "Benefits", + scTitleFr: "Prestations", + scPageNameEn: "https://www.canada.ca/en/services/benefits.html", + scPageNameFr: "https://www.canada.ca/fr/services/prestations.html", + }, + { + scTitleEn: "Dental coverage", + scTitleFr: "Couverture dentaire", + scPageNameEn: "https://www.canada.ca/en/services/benefits/dental.html", + scPageNameFr: + "https://www.canada.ca/fr/services/prestations/dentaire.html", + }, + { + scTitleEn: "Canadian Dental Care Plan", + scTitleFr: "Régime canadien de soins dentaires", + scPageNameEn: + "https://www.canada.ca/en/services/benefits/dental/dental-care-plan.html", + scPageNameFr: + "https://www.canada.ca/fr/services/prestations/dentaire/regime-soins-dentaires.html", + }, + ]; + + useEffect(() => { + Iif (props.adobeAnalyticsUrl) { + window.adobeDataLayer = window.adobeDataLayer || []; + window.adobeDataLayer.push({ event: "pageLoad" }); + } + }, []); + + return ( + <Layout + locale={props.locale} + langUrl={props.locale === "en" ? "/rsdc-demander" : "/cdcp-apply"} + dateModifiedOverride={"2024-04-30"} + excludeFooterFeedback={true} + breadcrumbItems={createBreadcrumbs(breadCrumbs, props.locale)} + showDisclaimer + preFooterTitle="Service Canada" + preFooterLink={t("cdcp.cdcpPreFooterLinkUrl")} + preFooterLinkText={t("cdcp.cdcpPreFooterLinkText")} + > + <Head> + {/* Primary HTML Meta Tags */} + <title>{t("cdcp.secondaryHeading")}</title> + + {/* DCMI Meta Tags */} + <meta name="dcterms.title" content={t("cdcp.tertiaryHeading")} /> + <meta + name="dcterms.language" + content={props.locale === "en" ? "eng" : "fra"} + title="ISO639-2/T" + /> + <meta + name="dcterms.creator" + content={ + props.locale === "en" + ? "Employment and Social Development Canada" + : "Emploi et Développement social Canada" + } + /> + <meta name="dcterms.accessRights" content="2" /> + <meta name="dcterms.service" content="ESDC-EDSC_SCLabs-LaboratoireSC" /> + <meta name="dcterms.spatial" content="Canada" /> + + {/* Open Graph / Facebook */} + <meta property="og:type" content="website" /> + <meta property="og:locale" content={props.locale} /> + </Head> + <section className="layout-container"> + <div className="grid grid-cols-12 gap-x-8"> + <div className="col-span-12"> + <p className="mt-12 text-multi-neutrals-grey85"> + {t("cdcp.secondaryHeading")} + </p> + <h1 + id="pageMainTitle" + className="mt-0 mb-8 pb-2 border-b border-multi-red-red50a" + > + {t("cdcp.primaryHeading")} + </h1> + </div> + <div className="col-span-12 xl:col-span-8"> + <p>{t("cdcp.toCompleteApplication")}</p> + <ul className="list-disc mt-5"> + <li className="ml-10"> + <p>{t("cdcp.listItems.item1")}</p> + </li> + <li className="ml-10"> + <p>{t("cdcp.listItems.item2")}</p> + </li> + <li className="ml-10"> + <p>{t("cdcp.listItems.item3")}</p> + </li> + <li className="ml-10"> + <p>{t("cdcp.listItems.item4")}</p> + </li> + <li className="ml-10"> + <p>{t("cdcp.listItems.item5")}</p> + </li> + </ul> + <h2 className="mt-10 mb-10">{t("cdcp.headingH2")}</h2> + <p>{t("cdcp.clickButtonToApply")}</p> + <div className="mt-10"> + <ActionButton + id="cdcp-button" + style="primary" + href={t("cdcp.buttonLink")} + custom="mb-8 !rounded-md" + text={t("cdcp.buttonText")} + icon="icon-chevron-right" + iconStyle="mt-0.5 ml-4" + iconEnd={true} + /> + </div> + </div> + </div> + </section> + </Layout> + ); +} + +export const getStaticProps = async ({ locale }) => { + return { + props: { + locale: locale, + adobeAnalyticsUrl: process.env.ADOBE_ANALYTICS_URL ?? null, + ...(await serverSideTranslations(locale, ["common"])), + }, + }; +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import Head from "next/head"; +import Link from "next/link"; +import { ActionButton } from "../components/atoms/ActionButton"; +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; +import { useTranslation } from "next-i18next"; +import { useRouter } from "next/router"; +import { useEffect, useState } from "react"; +import aemServiceInstance from "../services/aemServiceInstance"; + +export default function ErrorPage(props) { + const { t } = useTranslation("common"); + const { query } = useRouter(); + const [pageData] = useState(props.pageData.item); + + const statusCode = query.statusCode || ""; + const errorTitle = + query.errorTitle || pageData.scContentEn.json[0].content[0].value; + const errorTitleFr = + query.errorTitleFr || pageData.scContentFr.json[0].content[0].value; + const errorMessage = + query.errorMessage || pageData.scContentEn.json[1].content[0].value; + const errorMessageFr = + query.errorMessageFr || pageData.scContentFr.json[1].content[0].value; + + useEffect(() => { + Iif (props.adobeAnalyticsUrl) { + window.adobeDataLayer = window.adobeDataLayer || []; + window.adobeDataLayer.push({ event: "pageLoad" }); + } + }, []); + + return ( + <> + <Head> + {/* Primary HTML Meta Tags */} + <title data-gc-analytics-error={props.statusCode}> + {pageData.scContentEn.json[0].content[0].value} |{" "} + {pageData.scContentFr.json[0].content[0].value} + </title> + <link rel="schema.dcterms" href="http://purl.org/dc/terms/" /> + <meta content="width=device-width, initial-scale=1" name="viewport" /> + <meta + name="description" + content={ + props.locale === "en" + ? `${errorTitle}` + `${errorMessage}` + : `${errorTitleFr}` + `${errorMessageFr}` + } + /> + <meta name="author" content="Service Canada" /> + <link rel="icon" href="/favicon.ico" /> + <meta name="robots" content="noindex, nofollow" /> + + {/* DCMI Meta Tags */} + <meta + property="dcterms:title" + lang="en" + content="The web site has reported an error" + /> + <meta + property="dcterms:title" + lang="fr" + content="Le site Web a signalé une erreur" + /> + <meta + name="dcterms.language" + content={props.locale === "en" ? "eng" : "fra"} + title="ISO639-2" + /> + <meta property="dcterms:creator" lang="en" content="Service Canada" /> + <meta property="dcterms:creator" lang="fr" content="Service Canada" /> + + <meta + property="dcterms:subject" + lang="en" + title="gccore" + content="GV Government and Politics;Government services" + /> + <meta + property="dcterms:subject" + lang="fr" + title="gccore" + content="GV Gouvernement et vie politique;Services gouvernementaux" + /> + <meta + property="dcterms:description" + lang="en" + content="Error message stating that the site has reported an error." + /> + <meta + property="dcterms:description" + lang="fr" + content="Message d'erreur indiquant que le site a signalé une erreur." + /> + <meta + name="dcterms.creator" + content={ + props.locale === "en" + ? "Employment and Social Development Canada" + : "Emploi et Développement social Canada" + } + /> + + <meta name="dcterms.accessRights" content="2" /> + <meta name="dcterms.service" content="ESDC-EDSC_SCLabs-LaboratoireSC" /> + <meta name="dcterms.issued" title="W3CDTF" content="2021-06-28" /> + <meta name="dcterms.modified" title="W3CDTF" content="2021-12-16" /> + <meta property="dcterms:modified" content="2021-12-16" /> + <meta property="dcterms:issued" content="2021-06-28" /> + <meta + name="dcterms.subject" + content="GV Government and Politics;Government services" + /> + <meta name="dcterms.language" title="ISO639-2" content="eng" /> + + {/* Open Graph / Facebook */} + <meta property="og:type" content="website" /> + <meta property="og:locale" content={props.locale} /> + <meta + property="og:url" + content={ + "https://alpha.service.canada.ca/" + `${props.locale}` + "/error" + } + /> + <meta + property="og:title" + content="The web site has reported an error | Le site Web a signalé une erreur" + /> + <meta + property="og:description" + content={ + props.locale === "en" + ? `${errorTitle}` + `${errorMessage}` + : `${errorTitleFr}` + `${errorMessageFr}` + } + /> + <meta property="og:image" content={`${t("metaImage")}`} /> + <meta property="og:image:alt" content={`${t("siteTitle")}`} /> + + {/* Twitter */} + <meta property="twitter:card" content="summary_large_image" /> + <meta + property="twitter:url" + content={ + "https://alpha.service.canada.ca/" + `${props.locale}` + "/error" + } + /> + <meta + property="twitter:title" + content="The web site has reported an error | Le site Web a signalé une erreur" + /> + <meta name="twitter:creator" content="Service Canada" /> + <meta + property="twitter:description" + content={ + props.locale === "en" + ? `${errorTitle}` + `${errorMessage}` + : `${errorTitleFr}` + `${errorMessageFr}` + } + /> + <meta property="twitter:image" content={`${t("metaImage")}`} /> + <meta property="twitter:image:alt" content={`${t("siteTitle")}`} /> + </Head> + <div className="min-h-screen relative"> + <section className="layout-container pb-44"> + <div className="pt-6"> + <img + src={`https://www.canada.ca${ + props.locale === "en" + ? pageData.scGcImages[0].scImageEn._path + : pageData.scGcImages[0].scImageFr._path + }`} + alt={ + props.locale === "en" + ? pageData.scGcImages[0].scImageAltTextEn + : pageData.scGcImages[0].scImageAltTextFr + } + width={575} + height={59} + /> + </div> + <div className="flex flex-col lg:flex-row justify-between items-center lg:items-start mt-8"> + {/* Left Side (English section) */} + <div> + <div className="relative h-auto xl:w-96 xxl:w-400px lg:w-72 lg:h-500px mb-8 lg:mb-0"> + <h1 + className="font-bold font-display mb-4" + data-testid="heading-en" + > + {errorTitle} + </h1> + {statusCode ? ( + <p + className="font-bold font-body mb-8" + data-testid="statuscode-en" + > + {pageData.scContentEn.json[2].content[0].value} {statusCode} + </p> + ) : ( + "" + )} + <p + className="font-body text-p font-bold mb-4 leading-30px" + data-testid="errormessage-en" + > + {errorMessage} + </p> + {errorMessage === "Wrong URL" ? ( + <> + {/* Wrong URL English Section */} + <p className="font-body text-sm leading-30px mb-5"> + {pageData.scContentEn.json[3].content[0].value} + </p> + <ul> + <li className="flex"> + <span className="error404-link" /> + <p className="font-body text-sm leading-30px"> + {pageData.scContentEn.json[4].content[0].value} + </p> + </li> + <li className="flex"> + <span className="error404-link" /> + <p className="font-body text-sm leading-30px"> + {pageData.scContentEn.json[5].content[0].value} + <a + href={`mailto:${process.env.NEXT_PUBLIC_NOTIFY_REPORT_A_PROBLEM_EMAIL}`} + className="text-custom-blue-link underline" + > + { + process.env + .NEXT_PUBLIC_NOTIFY_REPORT_A_PROBLEM_EMAIL + } + </a>{" "} + {pageData.scContentEn.json[6].content[0].value} + </p> + </li> + </ul> + <p className="font-body text-sm leading-30px mt-5"> + {pageData.scContentEn.json[7].content[0].value} + </p> + </> + ) : errorMessage === "Expired URL" ? ( + <> + {/* Expired URL English Section */} + <p className="font-body text-sm leading-30px mb-5"> + {pageData.scContentEn.json[8].content[0].value} + </p> + <ul> + <li className="flex"> + <span className="error404-link" /> + <p className="font-body text-sm leading-30px"> + <Link + href="/en/home" + locale={false} + className="underline hover:text-canada-footer-hover-font-blue text-canada-footer-font" + > + {pageData.scContentEn.json[9].content[0].value} + </Link>{" "} + {pageData.scContentEn.json[9].content[1].value} + </p> + </li> + </ul> + <p className="font-body text-sm leading-30px mt-5"> + {pageData.scContentEn.json[7].content[0].value} + </p> + </> + ) : ( + /* General Error English Section */ + <div className="flex"> + <span className="error404-link" /> + <p className="font-body text-sm leading-30px"> + {pageData.scContentEn.json[10].content[0].value} + <Link + href="/en/home" + locale={false} + className="underline hover:text-canada-footer-hover-font-blue text-canada-footer-font" + > + {pageData.scContentEn.json[10].content[1].value} + </Link> + </p> + </div> + )} + </div> + </div> + <div className="flex items-center justify-center circle-background my-8 lg:mt-0 lightbulb-bg"> + <span className="relative lightbulb"> + <img + src={`https://www.canada.ca${ + props.locale === "en" + ? pageData.scImageList[0].scImageEn._path + : pageData.scImageList[0].scImageFr._path + }`} + alt="" + /> + </span> + </div> + {/* Right Side (French section) */} + <div> + <div + className="relative h-auto xl:w-96 xxl:w-400px lg:w-72 lg:h-500px mb-8 lg:mb-0" + lang="fr" + > + <h1 + className="font-bold font-display mb-4" + data-testid="heading-fr" + > + {errorTitleFr} + </h1> + {statusCode ? ( + <p + className="font-bold font-body mb-8" + data-testid="statuscode-fr" + > + {pageData.scContentFr.json[2].content[0].value} {statusCode} + </p> + ) : ( + "" + )} + <p + className="font-body text-p font-bold mb-4 leading-30px" + data-testid="errormessage-fr" + > + {errorMessageFr} + </p> + {errorMessageFr === "URL erronée" ? ( + <> + {/* Wrong URL French Section */} + <p className="font-body text-sm leading-30px mb-5"> + {pageData.scContentFr.json[3].content[0].value} + </p> + <ul> + <li className="flex"> + <span className="error404-link" /> + <p className="font-body text-sm leading-30px"> + {pageData.scContentFr.json[4].content[0].value} + </p> + </li> + <li className="flex"> + <span className="error404-link" /> + <p className="font-body text-sm leading-30px"> + {pageData.scContentFr.json[5].content[0].value} + <a + href={`mailto:${process.env.NEXT_PUBLIC_NOTIFY_REPORT_A_PROBLEM_EMAIL}`} + className="text-custom-blue-link underline" + > + { + process.env + .NEXT_PUBLIC_NOTIFY_REPORT_A_PROBLEM_EMAIL + } + </a>{" "} + {pageData.scContentFr.json[6].content[0].value} + </p> + </li> + </ul> + <p className="font-body text-sm leading-30px mt-5"> + {pageData.scContentFr.json[7].content[0].value} + </p> + </> + ) : errorMessageFr === "URL expirée" ? ( + <> + {/* Expired URL French Section */} + <p className="font-body text-sm leading-30px mb-5"> + {pageData.scContentFr.json[8].content[0].value} + </p> + <ul> + <li className="flex"> + <span className="error404-link" /> + <p className="font-body text-sm leading-30px"> + <Link + href="/fr/accueil" + locale={false} + className="underline hover:text-canada-footer-hover-font-blue text-canada-footer-font" + > + {pageData.scContentFr.json[9].content[0].value} + </Link> + {pageData.scContentFr.json[9].content[1].value} + </p> + </li> + </ul> + <p className="font-body text-sm leading-30px mt-5"> + {pageData.scContentFr.json[7].content[0].value} + </p> + </> + ) : ( + /* General Error French Section */ + <div className="flex"> + <span className="error404-link" /> + <p className="font-body text-sm leading-30px"> + {pageData.scContentFr.json[10].content[0].value} + <Link + href="/fr/accueil" + locale={false} + className="underline hover:text-canada-footer-hover-font-blue text-canada-footer-font" + > + {pageData.scContentFr.json[10].content[1].value} + </Link> + </p> + </div> + )} + </div> + </div> + </div> + </section> + </div> + <footer className="h-100px w-screen bg-footer-background-color absolute bottom-0"> + <div className="layout-container flex justify-between lg:flex-row-reverse pt-4 lg:pt-0 lg:mt-8"> + <ActionButton + id="errorTopOfPageButton" + href="#" + custom="text-left w-32 flex flex-col lg:hidden" + text="Top of page / Haut de la page" + icon="icon-up-caret" + iconEnd + /> + <span className="relative footer-logo"> + <img + src={`https://www.canada.ca${ + props.locale === "en" + ? pageData.scGcImages[1].scImageEn._path + : pageData.scGcImages[1].scImageFr._path + }`} + alt={ + props.locale === "en" + ? pageData.scGcImages[1].scImageAltTextEn + : pageData.scGcImages[1].scImageAltTextFr + } + /> + </span> + </div> + </footer> + </> + ); +} + +export const getStaticProps = async ({ locale }) => { + const { data } = await aemServiceInstance.getFragment("customErrorQuery"); + + return { + props: { + locale: locale, + adobeAnalyticsUrl: process.env.ADOBE_ANALYTICS_URL ?? null, + ...(await serverSideTranslations("en", ["common"])), + ...(await serverSideTranslations("fr", ["common"])), + pageData: data.sclabsErrorpageV1ByPath, + }, + }; +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 | 1x +1x +1x +1x +1x +1x +1x +1x +1x + +1x +2x +1x + +1x +1x + + + + + +1x + +1x + + + + + + + + +1x +1x +6x + + + +1x + + + + +1x + +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1x +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + + + + + + + | import Head from "next/head"; +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; +import { Layout } from "../components/organisms/Layout"; +import { useEffect } from "react"; +import Card from "../components/molecules/Card"; +import aemServiceInstance from "../services/aemServiceInstance"; +import { Heading } from "../components/molecules/Heading"; +import { ContextualAlert } from "../components/molecules/ContextualAlert"; +import Image from "next/image"; + +export default function Home(props) { + const pageData = props.pageData?.item; + const experimentsData = props.experimentsData; + + const currentProjects = experimentsData.filter((project) => { + return ( + project.scLabProjectStatus[0] === + "gc:custom/decd-endc/project-status/current" + ); + }); + + const sortedProjects = (objects) => { + // Order to sort the projects + const sortOrder = [ + "Benefits Finder", + "Making it easier to get benefits", + "Digital Standards Playbook", + "New dashboard for My Service Canada Account", + "Old Age Security Benefits Estimator", + "Benefits Navigator", + ]; + // Create a lookup for efficient ordering + const titleOrder = {}; + for (let i = 0; i < sortOrder.length; i++) { + titleOrder[sortOrder[i]] = i; + } + + // Sort the objects based on the lookup + return objects.sort((a, b) => { + return titleOrder[a.scTitleEn] - titleOrder[b.scTitleEn]; + }); + }; + + const displayCurrentProjects = sortedProjects(currentProjects).map( + (project) => ( + <li key={project.scId} className="list-none ml-0"> + <Card + showImage + showTag={ + project.scLabsNewExpiryDate && + Date.now() <= new Date(project.scLabsNewExpiryDate) + } + tagLabel={ + props.locale === "en" ? "New update" : "Nouvelle mise à jour" + } + tag="new_update" + imgSrc={ + props.locale === "en" + ? project.scSocialMediaImageEn._publishUrl + : project.scSocialMediaImageFr._publishUrl + } + imgAlt={ + props.locale === "en" + ? project.scSocialMediaImageAltTextEn + : project.scSocialMediaImageAltTextFr + } + imgHeight={ + project.scSocialMediaImageEn.height + ? project.scSocialMediaImageEn.height + : "" + } + imgWidth={ + project.scSocialMediaImageEn.width + ? project.scSocialMediaImageEn.width + : "" + } + title={props.locale === "en" ? project.scTitleEn : project.scTitleFr} + href={ + props.locale === "en" ? project.scPageNameEn : project.scPageNameFr + } + description={ + props.locale === "en" + ? project.scDescriptionEn.json[0].content[0].value + : project.scDescriptionFr.json[0].content[0].value + } + /> + </li> + ) + ); + + useEffect(() => { + Iif (props.adobeAnalyticsUrl) { + window.adobeDataLayer = window.adobeDataLayer || []; + window.adobeDataLayer.push({ event: "pageLoad" }); + } + }, []); + + return ( + <> + <Layout + locale={props.locale} + langUrl={ + props.locale === "en" ? pageData.scPageNameFr : pageData.scPageNameEn + } + dateModifiedOverride={pageData.scDateModifiedOverwrite} + > + <Head> + {/* Primary HTML Meta Tags */} + <title> + {props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr} + </title> + <meta + name="description" + content={ + props.locale === "en" + ? pageData.scDescriptionEn.json[0].content[0].value + : pageData.scDescriptionFr.json[0].content[0].value + } + /> + <meta name="author" content="Service Canada" /> + <link rel="icon" href="/favicon.ico" /> + <link rel="schema.dcterms" href="http://purl.org/dc/terms/" /> + <meta + name="keywords" + content={ + props.locale === "en" + ? pageData.scKeywordsEn + : pageData.scKeywordsFr + } + /> + + {/* DCMI Meta Tags */} + <meta + name="dcterms.title" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + <meta + name="dcterms.language" + content={props.locale === "en" ? "eng" : "fra"} + title="ISO639-2/T" + /> + <meta + name="dcterms.description" + content={ + props.locale === "en" + ? pageData.scDescriptionEn.json[0].content[0].value + : pageData.scDescriptionFr.json[0].content[0].value + } + /> + <meta + name="dcterms.subject" + title="gccore" + content={pageData.scSubject} + /> + <meta + name="dcterms.creator" + content={ + props.locale === "en" + ? "Employment and Social Development Canada" + : "Emploi et Développement social Canada" + } + /> + <meta name="dcterms.accessRights" content="2" /> + <meta + name="dcterms.service" + content="ESDC-EDSC_SCLabs-LaboratoireSC" + /> + <meta name="dcterms.issued" title="W3CDTF" content="2021-03-18" /> + <meta name="dcterms.modified" title="W3CDTF" content="2021-12-16" /> + <meta name="dcterms.spatial" content="Canada" /> + + {/* Open Graph / Facebook */} + <meta property="og:type" content="website" /> + <meta property="og:locale" content={props.locale} /> + <meta + property="og:url" + content={ + "https://alpha.service.canada.ca" + + `${ + props.locale === "en" + ? pageData.scPageNameEn + : pageData.scPageNameFr + }` + } + /> + <meta + property="og:title" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + <meta + property="og:description" + content={ + props.locale === "en" + ? pageData.scDescriptionEn.json[0].content[0].value + : pageData.scDescriptionFr.json[0].content[0].value + } + /> + <meta + property="og:image" + content={pageData.scSocialMediaImageEn._publishUrl} + /> + <meta + property="og:image:alt" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + + {/* Twitter */} + <meta property="twitter:card" content="summary_large_image" /> + <meta + property="twitter:url" + content={ + "https://alpha.service.canada.ca" + + `${ + props.locale === "en" + ? pageData.scPageNameEn + : pageData.scPageNameFr + }` + } + /> + <meta + property="twitter:title" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + <meta name="twitter:creator" content="Service Canada" /> + <meta + property="twitter:description" + content={ + props.locale === "en" + ? pageData.scDescriptionEn.json[0].content[0].value + : pageData.scDescriptionFr.json[0].content[0].value + } + /> + <meta + property="twitter:image" + content={pageData.scSocialMediaImageEn._publishUrl} + /> + <meta + property="twitter:image:alt" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + </Head> + <section className="layout-container"> + <div className="grid grid-cols-4"> + <div className="col-span-4"> + <Heading + tabIndex="-1" + id="pageMainTitle" + title={ + props.locale === "en" + ? pageData.scTitleEn + : pageData.scTitleFr + } + /> + </div> + <p className="font-body col-span-4 xl:col-span-2 row-start-2"> + {props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[1].content[0].value + : pageData.scFragments[0].scContentFr.json[1].content[0].value} + </p> + <p className="font-body col-span-4 xl:col-span-2 row-start-3 pt-4 xxl:pt-0"> + {props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[2].content[0].value + : pageData.scFragments[0].scContentFr.json[2].content[0].value} + </p> + <div className="hidden xl:grid col-span-2 col-start-3 row-start-2 row-span-2"> + <div className="flex justify-center"> + <span + className="w-full" + style={{ height: "260px", width: "380px", minWidth: "380px" }} + role="presentation" + > + <Image + src={ + props.locale === "en" + ? pageData.scFragments[1].scImageEn._publishUrl + : pageData.scFragments[1].scImageFr._publishUrl + } + alt="" + width={pageData.scFragments[1].scImageEn.width} + height={pageData.scFragments[1].scImageEn.height} + sizes="35vw" + priority + quality={100} + /> + </span> + </div> + </div> + </div> + <div className="lg:flex"> + <span className="w-full"> + <h2> + {props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[3].content[0].value + : pageData.scFragments[0].scContentFr.json[3].content[0] + .value}{" "} + </h2> + <p className="font-body"> + {props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[4].content[0].value + : pageData.scFragments[0].scContentFr.json[4].content[0] + .value}{" "} + </p> + <ul className="list-disc"> + <li className="ml-10"> + <p className="font-body"> + {props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[5].content[0] + .content[0].value + : pageData.scFragments[0].scContentFr.json[5].content[0] + .content[0].value}{" "} + </p> + </li> + <li className="ml-10"> + <p className="font-body"> + {props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[5].content[1] + .content[0].value + : pageData.scFragments[0].scContentFr.json[5].content[1] + .content[0].value}{" "} + </p> + </li> + </ul> + </span> + </div> + <h2> + {props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[6].content[0].value + : pageData.scFragments[0].scContentFr.json[6].content[0] + .value}{" "} + </h2> + <div className="mb-8"> + <ContextualAlert + id="info-alert" + type="info" + alert_icon_alt_text="info icon" + alert_icon_id="info icon" + message_heading={ + props.locale === "en" + ? pageData.scFragments[2].scTitleEn + : pageData.scFragments[2].scTitleFr + } + message_body={ + props.locale === "en" ? ( + <> + { + pageData.scFragments[2].scContentEn.json[0].content[0] + .value + } + <a + className="underline text-canada-footer-font hover:text-canada-footer-hover-font-blue" + href={ + pageData.scFragments[2].scContentEn.json[0].content[1] + .data.href + } + > + { + pageData.scFragments[2].scContentEn.json[0].content[1] + .value + } + </a> + { + pageData.scFragments[2].scContentEn.json[0].content[2] + .value + } + </> + ) : ( + <> + { + pageData.scFragments[2].scContentFr.json[0].content[0] + .value + } + <a + className="underline text-canada-footer-font hover:text-canada-footer-hover-font-blue" + href={ + pageData.scFragments[2].scContentFr.json[0].content[1] + .data.href + } + > + { + pageData.scFragments[2].scContentFr.json[0].content[1] + .value + } + </a> + { + pageData.scFragments[2].scContentEn.json[0].content[2] + .value + } + </> + ) + } + /> + </div> + <ul className="grid lg:grid-cols-2 gap-4 list-none ml-0"> + {displayCurrentProjects} + </ul> + </section> + </Layout> + </> + ); +} + +export const getStaticProps = async ({ locale }) => { + const { data: pageData } = await aemServiceInstance.getFragment( + "homePageQuery" + ); + const { data: experimentsData } = await aemServiceInstance.getFragment( + "projectQuery" + ); + + return { + props: { + locale: locale, + adobeAnalyticsUrl: process.env.ADOBE_ANALYTICS_URL ?? null, + pageData: pageData.sclabsPageV1ByPath, + experimentsData: experimentsData.sclabsPageV1List.items, + ...(await serverSideTranslations(locale, ["common"])), + }, + revalidate: process.env.ISR_ENABLED === "true" ? 10 : false, + }; +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +File | ++ | Statements | ++ | Branches | ++ | Functions | ++ | Lines | ++ |
---|---|---|---|---|---|---|---|---|---|
404.js | +
+
+ |
+ 76.92% | +20/26 | +40.9% | +9/22 | +66.66% | +2/3 | +80% | +20/25 | +
500.js | +
+
+ |
+ 76.92% | +20/26 | +40% | +8/20 | +66.66% | +2/3 | +80% | +20/25 | +
_app.js | +
+
+ |
+ 0% | +0/13 | +100% | +0/0 | +0% | +0/1 | +0% | +0/12 | +
cdcp-apply.js | +
+
+ |
+ 0% | +0/17 | +0% | +0/11 | +0% | +0/3 | +0% | +0/16 | +
error.js | +
+
+ |
+ 0% | +0/25 | +0% | +0/43 | +0% | +0/3 | +0% | +0/24 | +
home.js | +
+
+ |
+ 78.78% | +26/33 | +44.87% | +35/78 | +71.42% | +5/7 | +80.64% | +25/31 | +
index.js | +
+
+ |
+ 75% | +12/16 | +11.11% | +1/9 | +66.66% | +2/3 | +85.71% | +12/14 | +
notsupported.js | +
+
+ |
+ 62.5% | +15/24 | +44.18% | +19/43 | +40% | +2/5 | +65.21% | +15/23 | +
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 | 1x +1x +1x +1x +1x +1x + +1x +1x + +1x +1x + + + +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1x + + + + + + + | import Head from "next/head"; +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; +import { useTranslation } from "next-i18next"; +import { ActionButton } from "../components/atoms/ActionButton"; +import Link from "next/link"; +import { useEffect } from "react"; + +export default function Index(props) { + const { t } = useTranslation("common"); + + useEffect(() => { + Iif (props.adobeAnalyticsUrl) { + window.adobeDataLayer = window.adobeDataLayer || []; + window.adobeDataLayer.push({ event: "pageLoad" }); + } + document.documentElement.lang = "en"; + }, []); + + return ( + <> + <div className="splash-bg splash-image bg-splash-img-mobile xs:bg-splash-img bg-no-repeat fixed left-0 top-0 w-full h-full -z-1" /> + <Head> + {/* Primary HTML Meta Tags */} + <title>Service Canada Labs | Laboratoires de Service Canada</title> + <meta + name="description" + content="Explore the Service Canada Labs in English or French." + /> + <meta name="author" content="Service Canada" /> + <link rel="icon" href="/favicon.ico" /> + <link rel="schema.dcterms" href="http://purl.org/dc/terms/" /> + <meta content="width=device-width, initial-scale=1" name="viewport" /> + <meta name="robots" content="noindex, follow" /> + {/* DCMI Meta Tags */} + <meta + property="dcterms:title" + lang="en" + content="Service Canada Labs" + /> + <meta + property="dcterms:title" + lang="fr" + content="Laboratoires de Service Canada" + /> + <meta + name="dcterms.language" + content={props.locale === "en" ? "eng" : "fra"} + title="ISO639-2" + /> + <meta property="dcterms:creator" lang="en" content="Service Canada" /> + <meta property="dcterms:creator" lang="fr" content="Service Canada" /> + <meta name="dcterms.accessRights" content="2" /> + <meta name="dcterms.service" content="ESDC-EDSC_SCLabs-LaboratoireSC" /> + <meta name="dcterms.issued" content="2021-05-06" /> + <meta property="dcterms:modified" content="2021-12-16" /> + <meta name="dcterms.issued" title="W3CDTF" content="2021-05-06" /> + <meta name="dcterms.modified" title="W3CDTF" content="2021-12-16" /> + <meta + property="dcterms:description" + lang="en" + content="Explore the Service Canada Labs in English or French." + /> + <meta + property="dcterms:description" + lang="fr" + content="Explorez les laboratoires de Service Canda en français ou en anglais." + /> + <meta + property="dcterms:subject" + lang="en" + title="gccore" + content="GV Government and Politics;Government services" + /> + <meta + property="dcterms:subject" + lang="fr" + title="gccore" + content="GV Gouvernement et vie politique;Services gouvernementaux" + /> + {/* Open Graph / Facebook */} + <meta property="og:type" content="website" /> + <meta property="og:locale" content={props.locale} /> + <meta property="og:url" content={"https://alpha.service.canada.ca/"} /> + <meta + property="og:title" + content="Service Canada Labs | Laboratoires de Service Canada" + /> + <meta + property="og:description" + content="Explore the Service Canada Labs in English or French." + /> + <meta property="og:image" content={`${t("metaImage")}`} /> + <meta property="og:image:alt" content={`${t("siteTitle")}`} /> + {/* Twitter */} + <meta property="twitter:card" content="summary_large_image" /> + <meta + property="twitter:url" + content={"https://alpha.service.canada.ca/"} + /> + <meta + property="twitter:title" + content="Service Canada Labs | Laboratoires de Service Canada" + /> + <meta name="twitter:creator" content="Service Canada" /> + <meta + property="twitter:description" + content="Explore the Service Canada Labs in English or French." + /> + <meta property="twitter:image" content={`${t("metaImage")}`} /> + <meta property="twitter:image:alt" content={`${t("siteTitle")}`} /> + // Site ownership verification to use URL Inspection Tool + <meta + name="google-site-verification" + content="cJ7yrE6jUDOrRFwPgxPanWrgaRqI9l0qG0F9rqFhZxM" + /> + </Head> + <div className="h-full flex justify-center"> + <div className="splash-cta fixed flex flex-col sm:justify-center sm:items-center"> + <div className="z-10 bg-white h-auto min-w-300px w-300px xl:w-500px"> + <h1 className="sr-only">alpha.service.canada.ca</h1> + <div className="p-4"> + <img + src={"/sig-blk-en.svg"} + alt={"Government of Canada / Gouvernement du Canada"} + width="300" + height="35" + /> + </div> + <div className="flex w-max container mx-auto py-6 font-display"> + <h2 + className="text-p text-right xl:text-h4 mr-6 w-32 xl:w-40" + lang="en" + > + Service Canada Labs + </h2> + <h2 className="text-p xl:text-h4 w-32 xl:w-40" lang="fr"> + Laboratoires de Service Canada + </h2> + </div> + <div className="flex w-max container pb-6 mx-auto font-display"> + <ActionButton + id="english-button" + style="primary" + text="English" + lang="en" + custom="justify-center w-7.5rem xl:w-138px mr-6 text-lg" + href="/en/home" + /> + <ActionButton + id="french-button" + style="primary" + text="Français" + href="/fr/accueil" + lang="fr" + custom="justify-center w-7.5rem xl:w-138px text-lg" + /> + </div> + </div> + <div className="relative py-7 bg-splash-page-bottom text-p h-auto min-w-300px w-300px flex justify-between container p-6 xl:w-500px xl:items-center"> + <div className="w-28 text-base xl:text-p xl:w-max font-body"> + <Link + href="https://www.canada.ca/en/transparency/terms.html" + className="inline-block w-28 xl:w-max mr-0 hover:text-canada-footer-hover-font-blue text-canada-footer-font splash-link" + > + Terms & conditions + </Link> + <Link + href="https://www.canada.ca/fr/transparence/avis.html" + className="inline-block hover:text-canada-footer-hover-font-blue text-canada-footer-font" + lang="fr" + > + Avis + </Link> + </div> + <img + src="/wmms-blk.svg" + alt="Symbol of the Government of Canada / Symbole du gouvernement du Canada" + width="150" + height="25" + /> + </div> + </div> + </div> + </> + ); +} + +export const getServerSideProps = async ({ locale }) => ({ + props: { + locale: locale ?? "en", + adobeAnalyticsUrl: process.env.ADOBE_ANALYTICS_URL ?? null, + ...(await serverSideTranslations(locale, ["common"])), + }, +}); + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 | 1x +1x +1x +1x +1x +1x + +1x + +1x +1x +1x +1x +1x + +1x +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + | import Head from "next/head"; +import { useTranslation } from "next-i18next"; +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; +import { ActionButton } from "../components/atoms/ActionButton"; +import { useEffect } from "react"; +import { CopyToClipboard } from "../components/molecules/CopyToClipboard"; +import { useState } from "react"; +import aemServiceInstance from "../services/aemServiceInstance"; + +export default function notSupported(props) { + const { t } = useTranslation("common"); + const [enCopied, setEnCopied] = useState(false); + const [frCopied, setFrCopied] = useState(false); + const [pageData] = useState(props.pageData.item); + + useEffect(() => { + Iif (props.adobeAnalyticsUrl) { + window.adobeDataLayer = window.adobeDataLayer || []; + window.adobeDataLayer.push({ event: "pageLoad" }); + } + }, []); + + function onClickEn() { + setEnCopied(true); + setFrCopied(false); + } + + function onClickFr() { + setFrCopied(true); + setEnCopied(false); + } + return ( + <> + <Head> + {/* Primary HTML Meta Tags */} + <title data-gc-analytics-error="notSupported"> + {pageData.scContentEn.json[0].content[0].value} |{" "} + {pageData.scContentFr.json[0].content[0].value} + </title> + <meta + name="description" + content="Error message stating that the site will not work with Internet Explorer." + /> + <meta name="author" content="Service Canada" /> + <link rel="icon" href="/favicon.ico" /> + <link rel="schema.dcterms" href="http://purl.org/dc/terms/" /> + <meta content="width=device-width, initial-scale=1" name="viewport" /> + + {/* DCMI Meta Tags */} + <meta + property="dcterms:title" + lang="en" + content="Sorry, this site will not work with Internet Explorer" + /> + <meta + property="dcterms:title" + lang="fr" + content="Désolé, ce site ne fonctionne pas avec Internet Explorer" + /> + <meta + property="dcterms:description" + lang="en" + content="Error message stating that the site will not work with Internet Explorer." + /> + <meta + property="dcterms:description" + lang="fr" + content="Message d'erreur indiquant que le site ne fonctionne pas avec Internet Explorer." + /> + <meta + name="dcterms.language" + content={props.locale === "en" ? "eng" : "fra"} + title="ISO639-2" + /> + <meta + name="dcterms.creator" + content={ + props.locale === "en" + ? "Employment and Social Development Canada" + : "Emploi et Développement social Canada" + } + /> + <meta name="dcterms.accessRights" content="2" /> + <meta name="dcterms.service" content="ESDC-EDSC_SCLabs-LaboratoireSC" /> + <meta + property="dcterms:subject" + lang="fr" + title="gccore" + content="GV Gouvernement et vie politique;Services gouvernementaux" + /> + <meta + property="dcterms:subject" + lang="en" + title="gccore" + content="GV Government and Politics;Government services" + /> + <meta name="dcterms.issued" title="W3CDTF" content="2021-11-25" /> + <meta name="dcterms.modified" title="W3CDTF" content="2021-12-16" /> + <meta property="dcterms:issued" content="2021-11-25" /> + <meta property="dcterms:modified" content="2021-12-16" /> + + {/* Open Graph / Facebook */} + <meta property="og:type" content="website" /> + <meta property="og:locale" content={props.locale} /> + <meta + property="og:url" + content={ + "https://alpha.service.canada.ca/" + + `${props.locale}` + + "/notsupported" + } + /> + <meta + property="og:title" + content={`Browser not supported — ${t("siteTitle")}`} + /> + <meta + property="og:description" + content="Sorry, this site will not work with Internet Explorer | Désolé, ce + site ne fonctionne pas avec Internet Explorer" + /> + <meta property="og:image" content={`${t("metaImage")}`} /> + <meta property="og:image:alt" content={`${t("siteTitle")}`} /> + + {/* Twitter */} + <meta property="twitter:card" content="summary_large_image" /> + <meta + property="twitter:url" + content={ + "https://alpha.service.canada.ca/" + + `${props.locale}` + + "/notsupported" + } + /> + <meta + property="twitter:title" + content={`Browser not supported — ${t("siteTitle")}`} + /> + <meta name="twitter:creator" content="Service Canada" /> + <meta + property="twitter:description" + content="Sorry, this site will not work with Internet Explorer | Désolé, ce + site ne fonctionne pas avec Internet Explorer" + /> + <meta property="twitter:image" content={`${t("metaImage")}`} /> + <meta property="twitter:image:alt" content={`${t("siteTitle")}`} /> + </Head> + <div className="min-h-screen relative"> + <section className="xs:px-0 lg:mx-auto lg:px-6 container"> + <div className="pt-6"> + <img + src={`https://www.canada.ca${ + props.locale === "en" + ? pageData.scGcImages[0].scImageEn._path + : pageData.scGcImages[0].scImageFr._path + }`} + alt={ + props.locale === "en" + ? pageData.scGcImages[0].scImageAltTextEn + : pageData.scGcImages[0].scImageAltTextFr + } + width={575} + height={59} + /> + </div> + <div className="flex flex-col lg:flex-row justify-between items-center lg:items-start mt-8"> + <div> + <div className="relative h-auto xl:w-96 xxl:w-400px lg:w-72 xl:h-400px lg:h-500px mb-8 lg:mb-0"> + <h1 className="font-bold font-display mb-4"> + {pageData.scContentEn.json[0].content[0].value} + </h1> + <p className="font-body text-sm mb-4 leading-normal"> + {pageData.scContentEn.json[1].content[0].value} + </p> + </div> + </div> + <div className="flex items-center justify-center circle-background my-8 lg:mt-0 lightbulb-bg"> + <span className="relative lightbulb"> + <img + src={`https://www.canada.ca${ + props.locale === "en" + ? pageData.scImageList[0].scImageEn._path + : pageData.scImageList[0].scImageFr._path + }`} + alt="" + /> + </span> + </div> + <div> + <div + className="relative h-auto xl:w-96 xxl:w-400px lg:w-72 xl:h-400px lg:h-500px mb-8 lg:mb-0" + lang="fr" + > + <h1 className="font-bold font-display mb-4"> + {pageData.scContentFr.json[0].content[0].value} + </h1> + <p className="font-body text-sm mb-4 leading-normal"> + {pageData.scContentFr.json[1].content[0].value} + </p> + </div> + </div> + </div> + </section> + <section className="-mt-0 lg:-mt-36 sm:-mt-4 pb-5"> + <div className="flex items-center justify-center"> + <figure className="mx-4"> + <img + src={`https://www.canada.ca${ + props.locale === "en" + ? pageData.scImageList[1].scImageEn._path + : pageData.scImageList[1].scImageFr._path + }`} + alt={ + props.locale === "en" + ? pageData.scImageList[1].scImageAltTextEn + : pageData.scImageList[1].scImageAltTextFr + } + width="98" + height="98" + /> + <figcaption className="flex items-center justify-center"> + Chrome + </figcaption> + </figure> + <figure className="mx-4"> + <img + src={`https://www.canada.ca${ + props.locale === "en" + ? pageData.scImageList[2].scImageEn._path + : pageData.scImageList[2].scImageFr._path + }`} + alt={ + props.locale === "en" + ? pageData.scImageList[2].scImageAltTextEn + : pageData.scImageList[2].scImageAltTextFr + } + width="98" + height="98" + /> + <figcaption className="flex items-center justify-center"> + Safari + </figcaption> + </figure> + <figure className="mx-4"> + <img + src={`https://www.canada.ca${ + props.locale === "en" + ? pageData.scImageList[3].scImageEn._path + : pageData.scImageList[3].scImageFr._path + }`} + alt={ + props.locale === "en" + ? pageData.scImageList[3].scImageAltTextEn + : pageData.scImageList[3].scImageAltTextFr + } + width="94" + height="94" + /> + <figcaption className="pt-1.5 flex items-center justify-center"> + Edge + </figcaption> + </figure> + <figure className="mx-4"> + <img + src={`https://www.canada.ca${ + props.locale === "en" + ? pageData.scImageList[4].scImageEn._path + : pageData.scImageList[4].scImageFr._path + }`} + alt={ + props.locale === "en" + ? pageData.scImageList[4].scImageAltTextEn + : pageData.scImageList[4].scImageAltTextFr + } + width="98" + height="98" + /> + <figcaption className="flex items-center justify-center"> + Firefox + </figcaption> + </figure> + </div> + </section> + <section className="xs:px-0 lg:mx-auto lg:px-6 container pb-44"> + <div className="flex flex-col lg:flex-row justify-between items-center lg:items-start mt-8"> + <div className="relative h-auto xl:w-96 xxl:w-400px lg:w-72 mb-8 lg:mb-0"> + <p className="font-body text-sm mb-4 leading-normal"> + {pageData.scCopyToClipboardLabelEn} + </p> + <CopyToClipboard + buttonId="enClipboardButton" + buttonText={enCopied ? "Copied!" : "Copy link"} + buttonStyle={enCopied ? "ieButtonCopied" : "ieButton"} + value="http://alpha.service.canada.ca/home" + onClick={onClickEn} + id="enClipboard" + name="clipboard_en" + textFieldStyle="ieTextField" + aria_label="Copy the link below and paste in that browser." + /> + <p className="font-body text-sm pt-6 leading-normal"> + {pageData.scBrowserDownloadLinksEn.json[0].content[0].value} + </p> + <ul className="underline pt-4 font-body text-sm ieLinksList"> + <li className="browser-item"> + <a + href={ + pageData.scBrowserDownloadLinksEn.json[1].content[0] + .content[0].data.href + } + > + { + pageData.scBrowserDownloadLinksEn.json[1].content[0] + .content[0].value + } + </a> + </li> + <li className="browser-item"> + <a + href={ + pageData.scBrowserDownloadLinksEn.json[1].content[1] + .content[0].data.href + } + > + { + pageData.scBrowserDownloadLinksEn.json[1].content[1] + .content[0].value + } + </a> + </li> + <li className="browser-item"> + <a + href={ + pageData.scBrowserDownloadLinksEn.json[1].content[2] + .content[0].data.href + } + > + { + pageData.scBrowserDownloadLinksEn.json[1].content[2] + .content[0].value + } + </a> + </li> + <li className="browser-item"> + <a + href={ + pageData.scBrowserDownloadLinksEn.json[1].content[3] + .content[0].data.href + } + > + { + pageData.scBrowserDownloadLinksEn.json[1].content[3] + .content[0].value + } + </a> + </li> + </ul> + </div> + <div> + <div + className="relative h-auto xl:w-96 xxl:w-400px lg:w-72 mb-8 lg:mb-0" + lang="fr" + > + <p className="font-body text-sm mb-4 leading-normal"> + {pageData.scCopyToClipboardLabelFr} + </p> + <CopyToClipboard + buttonText={frCopied ? "Copié!" : "Copier lien"} + buttonId="frClipboardButton" + buttonStyle={frCopied ? "ieButtonCopied" : "ieButton"} + value="http://alpha.service.canada.ca/fr/home" + onClick={onClickFr} + id="frClipboard" + name="clipboard_fr" + textFieldStyle="ieTextField" + aria_label="Vous n'avez qu'à copier le lien ci-dessous et le coller dans ce navigateur." + /> + <p className="font-body text-sm pt-6 leading-normal"> + {pageData.scBrowserDownloadLinksFr.json[0].content[0].value} + </p> + <ul className="underline pt-4 font-body text-sm ieLinksList"> + <li className="browser-item"> + <a + href={ + pageData.scBrowserDownloadLinksFr.json[1].content[0] + .content[0].data.href + } + > + { + pageData.scBrowserDownloadLinksFr.json[1].content[0] + .content[0].value + } + </a> + </li> + <li className="browser-item"> + <a + href={ + pageData.scBrowserDownloadLinksFr.json[1].content[1] + .content[0].data.href + } + > + { + pageData.scBrowserDownloadLinksFr.json[1].content[1] + .content[0].value + } + </a> + </li> + <li className="browser-item"> + <a + href={ + pageData.scBrowserDownloadLinksFr.json[1].content[2] + .content[0].data.href + } + > + { + pageData.scBrowserDownloadLinksFr.json[1].content[2] + .content[0].value + } + </a> + </li> + <li className="browser-item"> + <a + href={ + pageData.scBrowserDownloadLinksFr.json[1].content[3] + .content[0].data.href + } + > + { + pageData.scBrowserDownloadLinksFr.json[1].content[3] + .content[0].value + } + </a> + </li> + </ul> + </div> + </div> + </div> + </section> + <footer className="h-100px w-screen bgGray absolute bottom-0"> + <div className="layout-container flex justify-between lg:flex-row-reverse pt-4 lg:pt-0 lg:mt-8"> + <ActionButton + id="404TopOfPageButton" + href="#" + custom="text-left w-32 flex flex-col lg:hidden" + text="Top of page / Haut de la page" + icon="icon-up-caret" + iconEnd + /> + <span className="relative footer-logo"> + <img + src={`https://www.canada.ca${ + props.locale === "en" + ? pageData.scGcImages[1].scImageEn._path + : pageData.scGcImages[1].scImageFr._path + }`} + alt={ + props.locale === "en" + ? pageData.scGcImages[1].scImageAltTextEn + : pageData.scGcImages[1].scImageAltTextFr + } + /> + </span> + </div> + </footer> + </div> + </> + ); +} + +export const getStaticProps = async ({ locale }) => { + const { data } = await aemServiceInstance.getFragment("notsupportedQuery"); + + return { + props: { + locale: locale, + adobeAnalyticsUrl: process.env.ADOBE_ANALYTICS_URL ?? null, + ...(await serverSideTranslations("en", ["common"])), + ...(await serverSideTranslations("fr", ["common"])), + pageData: data.sclabsErrorpageV1ByPath, + }, + }; +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import PageHead from "../../../components/fragment_renderer/PageHead"; +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; +import { Layout } from "../../../components/organisms/Layout"; +import { useEffect, useState } from "react"; +import aemServiceInstance from "../../../services/aemServiceInstance"; +import { getAllUpdateIds } from "../../../lib/utils/getAllUpdateIds"; +import { createBreadcrumbs } from "../../../lib/utils/createBreadcrumbs"; +import FragmentRender from "../../../components/fragment_renderer/FragmentRender"; +import { Heading } from "../../../components/molecules/Heading"; + +export default function BenefitFinderArticles(props) { + const [pageData] = useState(props.pageData); + const [dictionary] = useState(props.dictionary.items); + + useEffect(() => { + Iif (props.adobeAnalyticsUrl) { + window.adobeDataLayer = window.adobeDataLayer || []; + window.adobeDataLayer.push({ event: "pageLoad" }); + } + }, []); + + return ( + <> + <Layout + locale={props.locale} + langUrl={ + props.locale === "en" ? pageData.scPageNameFr : pageData.scPageNameEn + } + dateModifiedOverride={pageData.scDateModifiedOverwrite} + breadcrumbItems={createBreadcrumbs( + pageData.scBreadcrumbParentPages, + props.locale + )} + > + <PageHead pageData={pageData} locale={props.locale} /> + <section className="mb-12"> + <div className="layout-container"> + <Heading + tabIndex="-1" + id="pageMainTitle" + title={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + <div id="postedOnUpdatedOnSection" className="grid grid-cols-12"> + <p + className={`col-span-6 sm:col-span-4 ${ + props.locale === "en" ? "lg:col-span-2" : "lg:col-span-3" + } font-bold`} + > + {props.locale === "en" + ? dictionary[13].scTermEn + : dictionary[13].scTermFr} + </p> + <p className="col-span-6 col-start-7 sm:col-start-5 lg:col-span-2 md:col-start-5 mt-0"> + {pageData.scDateModifiedOverwrite} + </p> + <p + className={`row-start-2 col-span-6 sm:col-span-4 mt-0 ${ + props.locale === "en" ? "lg:col-span-2" : "lg:col-span-3" + } font-bold`} + > + {props.locale === "en" + ? dictionary[8].scTermEn + : dictionary[8].scTermFr} + </p> + <p className="row-start-2 col-span-6 col-start-7 sm:col-start-5 lg:col-span-2 md:col-start-5 mt-auto"> + {pageData.scDateModifiedOverwrite} + </p> + </div> + </div> + + {/* Main */} + <div id="mainContentSection"> + <FragmentRender + fragments={props.pageData.scFragments} + locale={props.locale} + /> + </div> + </section> + </Layout> + </> + ); +} + +export async function getStaticPaths() { + // Get pages data + const { data } = await aemServiceInstance.getFragment( + "benefitsNavigatorArticlesQuery" + ); + // Get paths for dynamic routes from the page name data + const paths = getAllUpdateIds(data.sclabsPageV1List.items); + paths.map((path) => (path.params.id = path.params.id.split("/").at(-1))); + return { + paths, + fallback: "blocking", + }; +} + +export const getStaticProps = async ({ locale, params }) => { + // Get pages data + const { data } = await aemServiceInstance.getFragment( + "benefitsFinderArticlesQuery" + ); + // get dictionary + const { data: dictionary } = await aemServiceInstance.getFragment( + "dictionaryQuery" + ); + const pages = data.sclabsPageV1List.items; + // Return page data that matches the current page being built + const pageData = pages.filter((page) => { + return ( + (locale === "en" ? page.scPageNameEn : page.scPageNameFr) + .split("/") + .at(-1) === params.id + ); + }); + + Iif (!pageData || !pageData.length) { + return { + notFound: true, + }; + } + + return { + props: { + locale: locale, + pageData: pageData[0], + dictionary: dictionary.dictionaryV1List, + adobeAnalyticsUrl: process.env.ADOBE_ANALYTICS_URL ?? null, + ...(await serverSideTranslations(locale, ["common", "vc"])), + }, + revalidate: process.env.ISR_ENABLED === "true" ? 10 : false, + }; +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ ++ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 | 1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x + +1x +2x +1x +1x + + +21x + + + + + + +1x +2x + + + + + + + + + + + + + + + + + + + + + + + + + +1x +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + + + + + + + + + + | import Head from "next/head"; +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; +import { Layout } from "../../../components/organisms/Layout"; +import { useEffect, useState } from "react"; +import aemServiceInstance from "../../../services/aemServiceInstance"; +import { ProjectInfo } from "../../../components/atoms/ProjectInfo"; +import Card from "../../../components/molecules/Card"; +import { createBreadcrumbs } from "../../../lib/utils/createBreadcrumbs"; +import { Heading } from "../../../components/molecules/Heading"; +import Image from "next/image"; +import stageDictionary from "../../../lib/utils/stageDictionary"; +import { sortUpdatesByDate } from "../../../lib/utils/sortUpdatesByDate"; +import FragmentRender from "../../../components/fragment_renderer/FragmentRender"; + +export default function BenefitsFinderOverview(props) { + const [pageData] = useState(props.pageData.item); + const updatesData = sortUpdatesByDate(props.updatesData); + const [filteredDictionary] = useState( + props.dictionary.items.filter( + (item) => + item.scId === "STARTED" || + item.scId === "ENDED" || + item.scId === "PROJECT-STAGE" || + item.scId === "SUMMARY" + ) + ); + + const displayProjectUpdates = updatesData.map((update) => ( + <li key={update.scId} className="list-none ml-0 col-span-12 lg:col-span-4"> + <Card + showImage + imgSrc={ + props.locale === "en" + ? `https://www.canada.ca${update.scSocialMediaImageEn?._path}` + : `https://www.canada.ca${update.scSocialMediaImageFr?._path}` + } + imgAlt={ + props.locale === "en" + ? update.scSocialMediaImageAltTextEn + : update.scSocialMediaImageAltTextFr + } + imgHeight={update.scSocialMediaImageEn.height} + imgWidth={update.scSocialMediaImageEn.width} + title={props.locale === "en" ? update.scTitleEn : update.scTitleFr} + href={props.locale === "en" ? update.scPageNameEn : update.scPageNameFr} + description={`${ + props.locale === "en" + ? props.dictionary.items[13].scTermEn + : props.dictionary.items[13].scTermFr + } ${update.scDateModifiedOverwrite}`} + /> + </li> + )); + + useEffect(() => { + Iif (props.adobeAnalyticsUrl) { + window.adobeDataLayer = window.adobeDataLayer || []; + window.adobeDataLayer.push({ event: "pageLoad" }); + } + }, []); + + return ( + <> + <Layout + locale={props.locale} + langUrl={ + props.locale === "en" ? pageData.scPageNameFr : pageData.scPageNameEn + } + dateModifiedOverride={pageData.scDateModifiedOverwrite} + breadcrumbItems={createBreadcrumbs( + pageData.scBreadcrumbParentPages, + props.locale + )} + > + <Head> + {/* Primary HTML Meta Tags */} + <title> + {props.locale === "en" + ? `${pageData.scTitleEn} - Service Canada Labs` + : `${pageData.scTitleFr} - Laboratoires de Service Canada`} + </title> + <meta + name="description" + content={ + props.locale === "en" + ? pageData.scDescriptionEn.json[0].content[0].value + : pageData.scDescriptionFr.json[0].content[0].value + } + /> + <meta name="author" content="Service Canada" /> + <link rel="icon" href="/favicon.ico" /> + <link + rel="canonical" + href={ + "https://alpha.service.canada.ca" + + `${ + props.locale === "en" + ? pageData.scPageNameEn + : pageData.scPageNameFr + }` + } + /> + <link rel="schema.dcterms" href="http://purl.org/dc/terms/" /> + <meta + name="keywords" + content={ + props.locale === "en" + ? pageData.scKeywordsEn + : pageData.scKeywordsFr + } + /> + + {/* DCMI Meta Tags */} + <meta + name="dcterms.title" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + <meta + name="dcterms.language" + content={props.locale === "en" ? "eng" : "fra"} + title="ISO639-2/T" + /> + <meta + name="dcterms.creator" + content={ + props.locale === "en" + ? "Employment and Social Development Canada" + : "Emploi et Développement social Canada" + } + /> + <meta name="dcterms.accessRights" content="2" /> + <meta + name="dcterms.service" + content="ESDC-EDSC_SCLabs-LaboratoireSC" + /> + <meta name="dcterms.issued" title="W3CDTF" content="2021-07-20" /> + + <meta name="dcterms.modified" title="W3CDTF" content="2021-12-16" /> + <meta + name="dcterms.description" + content={ + props.locale === "en" + ? pageData.scDescriptionEn.json[0].content[0].value + : pageData.scDescriptionFr.json[0].content[0].value + } + /> + <meta + name="dcterms.subject" + title="gccore" + content={pageData.scSubject} + /> + <meta name="dcterms.spatial" content="Canada" /> + + {/* Open Graph / Facebook */} + <meta property="og:type" content="website" /> + <meta property="og:locale" content={props.locale} /> + <meta + property="og:url" + content={ + "https://alpha.service.canada.ca" + + `${ + props.locale === "en" + ? pageData.scPageNameEn + : pageData.scPageNameFr + }` + } + /> + <meta + property="og:title" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + <meta + property="og:description" + content={ + props.locale === "en" + ? pageData.scDescriptionEn.json[0].content[0].value + : pageData.scDescriptionFr.json[0].content[0].value + } + /> + <meta + property="og:image" + content={pageData.scFragments[2].scImageEn._publishUrl} + /> + <meta + property="og:image:alt" + content={ + props.locale === "en" + ? pageData.scFragments[2].scImageAltTextEn + : pageData.scFragments[2].scImageAltTextFr + } + /> + + {/* Twitter */} + <meta property="twitter:card" content="summary_large_image" /> + <meta + property="twitter:url" + content={ + "https://alpha.service.canada.ca" + + `${ + props.locale === "en" + ? pageData.scPageNameEn + : pageData.scPageNameFr + }` + } + /> + <meta + property="twitter:title" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + <meta name="twitter:creator" content="Service Canada" /> + <meta + property="twitter:description" + content={ + props.locale === "en" + ? pageData.scDescriptionEn.json[0].content[0].value + : pageData.scDescriptionFr.json[0].content[0].value + } + /> + <meta + property="twitter:image" + content={pageData.scFragments[2].scImageEn._publishUrl} + /> + <meta + property="twitter:image:alt" + content={ + props.locale === "en" + ? pageData.scFragments[2].scImageAltTextEn + : pageData.scFragments[2].scImageAltTextFr + } + /> + </Head> + + <div className="layout-container"> + <section aria-labelledby="pageMainTitle"> + <div className="flex flex-col break-words lg:grid lg:grid-cols-2"> + <div className="col-span-2"> + <Heading + tabIndex="-1" + id="pageMainTitle" + title={ + props.locale === "en" + ? pageData.scTitleEn + : pageData.scTitleFr + } + /> + </div> + <div className="hidden lg:grid row-span-2 row-start-2 col-start-2 p-0 mx-4"> + <div className="flex justify-center"> + <div className="object-fill max-w-350px"> + <Image + src={ + props.locale === "en" + ? pageData.scFragments[2].scImageEn._publishUrl + : pageData.scFragments[2].scImageFr._publishUrl + } + alt={ + props.locale === "en" + ? pageData.scFragments[2].scImageAltTextEn + : pageData.scFragments[2].scImageAltTextFr + } + width={pageData.scFragments[2].scImageEn.width} + height={pageData.scFragments[2].scImageEn.height} + priority + sizes="33vw" + quality={100} + /> + </div> + </div> + </div> + <p className="row-start-2 font-body text-lg mb-4"> + {props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[1].content[0].value + : pageData.scFragments[0].scContentFr.json[1].content[0] + .value} + </p> + <div className="row-start-3"> + <ProjectInfo + locale={props.locale} + termStarted={ + props.locale === "en" + ? filteredDictionary[2].scTermEn + : filteredDictionary[2].scTermFr + } + termStage={ + props.locale === "en" + ? filteredDictionary[1].scTermEn + : filteredDictionary[1].scTermFr + } + termSummary={ + props.locale === "en" + ? filteredDictionary[3].scTermEn + : filteredDictionary[3].scTermFr + } + dateStarted={ + pageData.scFragments[0].scContentEn.json[2].content[0].value + } + term={ + props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[0].content[0] + .value + " " + : pageData.scFragments[0].scContentFr.json[0].content[0] + .value + " " + } + definition={ + props.locale === "en" + ? pageData.scFragments[1].scContentEn.json[0].content[1] + .value + : pageData.scFragments[1].scContentFr.json[0].content[1] + .value + } + information={ + props.locale === "en" + ? pageData.scFragments[1].scTitleEn + : pageData.scFragments[1].scTitleFr + } + stage={ + props.locale === "en" + ? stageDictionary.en[pageData.scLabProjectStage] + : stageDictionary.fr[pageData.scLabProjectStage] + } + summary={ + props.locale === "en" + ? pageData.scLabProjectSummaryEn.json[0].content[0].value + : pageData.scLabProjectSummaryFr.json[0].content[0].value + } + /> + </div> + <strong className="font-body text-p pt-8"> + {props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[5].content[0].value + : pageData.scFragments[0].scContentFr.json[5].content[0] + .value} + </strong> + </div> + </section> + </div> + + <FragmentRender + fragments={pageData.scFragments.slice(3)} + locale={props.locale} + /> + <div className="layout-container"> + {updatesData.length === 0 ? null : ( + <section id="projectUpdates"> + <h2> + {props.locale === "en" + ? "Project updates" + : "Mises à jour du projet"} + </h2> + <ul className="grid lg:grid-cols-12 gap-x-4 lg:gap-y-12 list-none ml-0 mb-12"> + {displayProjectUpdates} + </ul> + </section> + )} + </div> + </Layout> + </> + ); +} + +export const getStaticProps = async ({ locale }) => { + // get page data from AEM + const { data: pageData } = await aemServiceInstance.getFragment( + "benefitsFinderQuery" + ); + // get dictionary + const { data: dictionary } = await aemServiceInstance.getFragment( + "dictionaryQuery" + ); + + return { + props: { + locale: locale, + adobeAnalyticsUrl: process.env.ADOBE_ANALYTICS_URL ?? null, + pageData: pageData.sclabsPageV1ByPath, + updatesData: pageData.sclabsPageV1ByPath.item.scLabProjectUpdates, + dictionary: dictionary.dictionaryV1List, + ...(await serverSideTranslations(locale, ["common"])), + }, + revalidate: process.env.ISR_ENABLED === "true" ? 10 : false, + }; +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import PageHead from "../../../components/fragment_renderer/PageHead"; +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; +import { Layout } from "../../../components/organisms/Layout"; +import { useEffect, useState } from "react"; +import aemServiceInstance from "../../../services/aemServiceInstance"; +import { getAllUpdateIds } from "../../../lib/utils/getAllUpdateIds"; +import { createBreadcrumbs } from "../../../lib/utils/createBreadcrumbs"; +import FragmentRender from "../../../components/fragment_renderer/FragmentRender"; +import { Heading } from "../../../components/molecules/Heading"; + +export default function BenefitNavigatorArticles(props) { + const [pageData] = useState(props.pageData); + const [dictionary] = useState(props.dictionary.items); + + useEffect(() => { + Iif (props.adobeAnalyticsUrl) { + window.adobeDataLayer = window.adobeDataLayer || []; + window.adobeDataLayer.push({ event: "pageLoad" }); + } + }, []); + + return ( + <> + <Layout + locale={props.locale} + langUrl={ + props.locale === "en" ? pageData.scPageNameFr : pageData.scPageNameEn + } + dateModifiedOverride={pageData.scDateModifiedOverwrite} + breadcrumbItems={createBreadcrumbs( + pageData.scBreadcrumbParentPages, + props.locale + )} + > + <PageHead pageData={pageData} locale={props.locale} /> + <section className="mb-12"> + <div className="layout-container"> + <Heading + tabIndex="-1" + id="pageMainTitle" + title={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + <div id="postedOnUpdatedOnSection" className="grid grid-cols-12"> + <p + className={`col-span-6 sm:col-span-4 ${ + props.locale === "en" ? "lg:col-span-2" : "lg:col-span-3" + } font-bold`} + > + {props.locale === "en" + ? dictionary[13].scTermEn + : dictionary[13].scTermFr} + </p> + <p className="col-span-6 col-start-7 sm:col-start-5 lg:col-span-2 md:col-start-5 mt-0"> + {pageData.scDateModifiedOverwrite} + </p> + <p + className={`row-start-2 col-span-6 sm:col-span-4 mt-0 ${ + props.locale === "en" ? "lg:col-span-2" : "lg:col-span-3" + } font-bold`} + > + {props.locale === "en" + ? dictionary[8].scTermEn + : dictionary[8].scTermFr} + </p> + <p className="row-start-2 col-span-6 col-start-7 sm:col-start-5 lg:col-span-2 md:col-start-5 mt-auto"> + {pageData.scDateModifiedOverwrite} + </p> + </div> + </div> + + {/* Main */} + <div id="mainContentSection"> + <FragmentRender + fragments={props.pageData.scFragments} + locale={props.locale} + /> + </div> + </section> + </Layout> + </> + ); +} + +export async function getStaticPaths() { + // Get pages data + const { data } = await aemServiceInstance.getFragment( + "benefitsNavigatorArticlesQuery" + ); + // Get paths for dynamic routes from the page name data + const paths = getAllUpdateIds(data.sclabsPageV1List.items); + paths.map((path) => (path.params.id = path.params.id.split("/").at(-1))); + return { + paths, + fallback: "blocking", + }; +} + +export const getStaticProps = async ({ locale, params }) => { + // Get pages data + const { data } = await aemServiceInstance.getFragment( + "benefitsNavigatorArticlesQuery" + ); + // get dictionary + const { data: dictionary } = await aemServiceInstance.getFragment( + "dictionaryQuery" + ); + const pages = data.sclabsPageV1List.items; + // Return page data that matches the current page being built + const pageData = pages.filter((page) => { + return ( + (locale === "en" ? page.scPageNameEn : page.scPageNameFr) + .split("/") + .at(-1) === params.id + ); + }); + + Iif (!pageData || !pageData.length) { + return { + notFound: true, + }; + } + + return { + props: { + locale: locale, + pageData: pageData[0], + dictionary: dictionary.dictionaryV1List, + adobeAnalyticsUrl: process.env.ADOBE_ANALYTICS_URL ?? null, + ...(await serverSideTranslations(locale, ["common", "vc"])), + }, + revalidate: process.env.ISR_ENABLED === "true" ? 10 : false, + }; +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ ++ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 +484 +485 +486 +487 +488 +489 +490 +491 +492 +493 +494 +495 +496 +497 +498 +499 +500 +501 +502 +503 +504 +505 +506 +507 +508 +509 +510 +511 +512 +513 +514 +515 +516 +517 +518 +519 +520 +521 +522 +523 +524 +525 +526 +527 +528 +529 +530 +531 +532 +533 +534 +535 +536 +537 +538 +539 +540 +541 +542 +543 +544 +545 +546 +547 +548 +549 +550 +551 +552 +553 +554 +555 +556 +557 +558 +559 +560 +561 +562 +563 +564 +565 +566 +567 +568 +569 +570 +571 +572 +573 +574 +575 +576 +577 +578 +579 +580 +581 +582 +583 +584 +585 +586 +587 +588 +589 +590 +591 +592 +593 +594 +595 +596 +597 +598 +599 +600 +601 +602 +603 +604 +605 +606 +607 +608 +609 +610 +611 +612 +613 +614 +615 +616 +617 +618 +619 +620 +621 +622 +623 +624 +625 +626 +627 +628 +629 +630 +631 +632 +633 +634 +635 +636 +637 +638 +639 +640 +641 +642 +643 +644 +645 +646 +647 +648 +649 +650 +651 +652 +653 +654 | 1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x + +1x +2x +1x +1x + + +21x + + + + + + +1x +2x + + + + + + + + + + + + + + + + + + + + + + + + + +1x +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + + + + + + + + + + | import Head from "next/head"; +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; +import { Layout } from "../../../components/organisms/Layout"; +import { useEffect, useState } from "react"; +import aemServiceInstance from "../../../services/aemServiceInstance"; +import { ProjectInfo } from "../../../components/atoms/ProjectInfo"; +import Card from "../../../components/molecules/Card"; +import { createBreadcrumbs } from "../../../lib/utils/createBreadcrumbs"; +import { Heading } from "../../../components/molecules/Heading"; +import { Collapse } from "../../../components/molecules/Collapse"; +import Image from "next/image"; +import stageDictionary from "../../../lib/utils/stageDictionary"; +import TextRender from "../../../components/text_node_renderer/TextRender"; +import { sortUpdatesByDate } from "../../../lib/utils/sortUpdatesByDate"; +import { ContextualAlert } from "../../../components/molecules/ContextualAlert"; + +export default function BenefitsNavigatorOverview(props) { + const [pageData] = useState(props.pageData.item); + const updatesData = sortUpdatesByDate(props.updatesData); + const [filteredDictionary] = useState( + props.dictionary.items.filter( + (item) => + item.scId === "STARTED" || + item.scId === "ENDED" || + item.scId === "PROJECT-STAGE" || + item.scId === "SUMMARY" + ) + ); + + const displayProjectUpdates = updatesData.map((update) => ( + <li key={update.scId} className="list-none ml-0 col-span-12 lg:col-span-4"> + <Card + showImage + imgSrc={ + props.locale === "en" + ? `https://www.canada.ca${update.scSocialMediaImageEn?._path}` + : `https://www.canada.ca${update.scSocialMediaImageFr?._path}` + } + imgAlt={ + props.locale === "en" + ? update.scSocialMediaImageAltTextEn + : update.scSocialMediaImageAltTextFr + } + imgHeight={update.scSocialMediaImageEn.height} + imgWidth={update.scSocialMediaImageEn.width} + title={props.locale === "en" ? update.scTitleEn : update.scTitleFr} + href={props.locale === "en" ? update.scPageNameEn : update.scPageNameFr} + description={`${ + props.locale === "en" + ? props.dictionary.items[13].scTermEn + : props.dictionary.items[13].scTermFr + } ${update.scDateModifiedOverwrite}`} + /> + </li> + )); + + useEffect(() => { + Iif (props.adobeAnalyticsUrl) { + window.adobeDataLayer = window.adobeDataLayer || []; + window.adobeDataLayer.push({ event: "pageLoad" }); + } + }, []); + + return ( + <> + <Layout + locale={props.locale} + langUrl={ + props.locale === "en" ? pageData.scPageNameFr : pageData.scPageNameEn + } + dateModifiedOverride={pageData.scDateModifiedOverwrite} + breadcrumbItems={createBreadcrumbs( + pageData.scBreadcrumbParentPages, + props.locale + )} + > + <Head> + {/* Primary HTML Meta Tags */} + <title> + {props.locale === "en" + ? `${pageData.scTitleEn} - Service Canada Labs` + : `${pageData.scTitleFr} - Laboratoires de Service Canada`} + </title> + <meta + name="description" + content={ + props.locale === "en" + ? pageData.scDescriptionEn.json[0].content[0].value + : pageData.scDescriptionFr.json[0].content[0].value + } + /> + <meta name="author" content="Service Canada" /> + <link rel="icon" href="/favicon.ico" /> + <link + rel="canonical" + href={ + "https://alpha.service.canada.ca" + + `${ + props.locale === "en" + ? pageData.scPageNameEn + : pageData.scPageNameFr + }` + } + /> + <link rel="schema.dcterms" href="http://purl.org/dc/terms/" /> + <meta + name="keywords" + content={ + props.locale === "en" + ? pageData.scKeywordsEn + : pageData.scKeywordsFr + } + /> + + {/* DCMI Meta Tags */} + <meta + name="dcterms.title" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + <meta + name="dcterms.language" + content={props.locale === "en" ? "eng" : "fra"} + title="ISO639-2/T" + /> + <meta + name="dcterms.creator" + content={ + props.locale === "en" + ? "Employment and Social Development Canada" + : "Emploi et Développement social Canada" + } + /> + <meta name="dcterms.accessRights" content="2" /> + <meta + name="dcterms.service" + content="ESDC-EDSC_SCLabs-LaboratoireSC" + /> + <meta name="dcterms.issued" title="W3CDTF" content="2021-07-20" /> + + <meta name="dcterms.modified" title="W3CDTF" content="2021-12-16" /> + <meta + name="dcterms.description" + content={ + props.locale === "en" + ? pageData.scDescriptionEn.json[0].content[0].value + : pageData.scDescriptionFr.json[0].content[0].value + } + /> + <meta + name="dcterms.subject" + title="gccore" + content={pageData.scSubject} + /> + <meta name="dcterms.spatial" content="Canada" /> + + {/* Open Graph / Facebook */} + <meta property="og:type" content="website" /> + <meta property="og:locale" content={props.locale} /> + <meta + property="og:url" + content={ + "https://alpha.service.canada.ca" + + `${ + props.locale === "en" + ? pageData.scPageNameEn + : pageData.scPageNameFr + }` + } + /> + <meta + property="og:title" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + <meta + property="og:description" + content={ + props.locale === "en" + ? pageData.scDescriptionEn.json[0].content[0].value + : pageData.scDescriptionFr.json[0].content[0].value + } + /> + <meta + property="og:image" + content={pageData.scFragments[1].scImageEn._publishUrl} + /> + <meta + property="og:image:alt" + content={ + props.locale === "en" + ? pageData.scFragments[1].scImageAltTextEn + : pageData.scFragments[1].scImageAltTextFr + } + /> + + {/* Twitter */} + <meta property="twitter:card" content="summary_large_image" /> + <meta + property="twitter:url" + content={ + "https://alpha.service.canada.ca" + + `${ + props.locale === "en" + ? pageData.scPageNameEn + : pageData.scPageNameFr + }` + } + /> + <meta + property="twitter:title" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + <meta name="twitter:creator" content="Service Canada" /> + <meta + property="twitter:description" + content={ + props.locale === "en" + ? pageData.scDescriptionEn.json[0].content[0].value + : pageData.scDescriptionFr.json[0].content[0].value + } + /> + <meta + property="twitter:image" + content={pageData.scFragments[1].scImageEn._publishUrl} + /> + <meta + property="twitter:image:alt" + content={ + props.locale === "en" + ? pageData.scFragments[1].scImageAltTextEn + : pageData.scFragments[1].scImageAltTextFr + } + /> + </Head> + + <div className="layout-container"> + <section aria-labelledby="pageMainTitle"> + <div className="flex flex-col break-words lg:grid lg:grid-cols-2"> + <div className="col-span-2"> + <Heading + tabIndex="-1" + id="pageMainTitle" + title={ + props.locale === "en" + ? pageData.scTitleEn + : pageData.scTitleFr + } + /> + <div className="mb-10 max-w-[76ch]"> + <ContextualAlert + id="alert" + type="warning" + message_heading={ + props.locale === "en" + ? pageData.scFragments[0].scTitleEn + : pageData.scFragments[0].scTitleFr + } + message_body={ + <TextRender + data={ + props.locale === "en" + ? pageData.scFragments[0].scContentEn.json + : pageData.scFragments[0].scContentFr.json + } + /> + } + alert_icon_alt_text="" + alert_icon_id="project-status-cta-icon" + /> + </div> + </div> + <div className="hidden lg:grid row-span-2 row-start-2 col-start-2 p-0 mx-4"> + <div className="flex justify-center"> + <div className="object-fill max-w-350px"> + <Image + src={ + props.locale === "en" + ? pageData.scFragments[1].scImageEn._publishUrl + : pageData.scFragments[1].scImageFr._publishUrl + } + alt={ + props.locale === "en" + ? pageData.scFragments[1].scImageAltTextEn + : pageData.scFragments[1].scImageAltTextFr + } + width={pageData.scFragments[1].scImageEn.width} + height={pageData.scFragments[1].scImageEn.height} + priority + sizes="33vw" + quality={100} + /> + </div> + </div> + </div> + <p className="row-start-2 font-body text-lg mb-4"> + {props.locale === "en" + ? pageData.scFragments[3].scContentEn.json[1].content[0].value + : pageData.scFragments[3].scContentFr.json[1].content[0] + .value} + </p> + <div className="row-start-3"> + <ProjectInfo + locale={props.locale} + termStarted={ + props.locale === "en" + ? filteredDictionary[2].scTermEn + : filteredDictionary[2].scTermFr + } + termStage={ + props.locale === "en" + ? filteredDictionary[1].scTermEn + : filteredDictionary[1].scTermFr + } + termSummary={ + props.locale === "en" + ? filteredDictionary[3].scTermEn + : filteredDictionary[3].scTermFr + } + dateStarted={ + pageData.scFragments[3].scContentEn.json[2].content[0].value + } + term={ + props.locale === "en" + ? pageData.scFragments[2].scContentEn.json[0].content[0] + .value + " " + : pageData.scFragments[2].scContentFr.json[0].content[0] + .value + " " + } + definition={ + props.locale === "en" + ? pageData.scFragments[2].scContentEn.json[0].content[1] + .value + : pageData.scFragments[2].scContentFr.json[0].content[1] + .value + } + information={ + props.locale === "en" + ? pageData.scFragments[2].scTitleEn + : pageData.scFragments[2].scTitleFr + } + stage={ + props.locale === "en" + ? stageDictionary.en[pageData.scLabProjectStage] + : stageDictionary.fr[pageData.scLabProjectStage] + } + summary={ + props.locale === "en" + ? pageData.scFragments[3].scContentEn.json[4].content[0] + .value + : pageData.scFragments[3].scContentFr.json[4].content[0] + .value + } + /> + </div> + </div> + </section> + <div className="grid grid-cols-12"> + <h2 className="col-span-12"> + {props.locale === "en" + ? pageData.scFragments[4].scContentEn.json[0].content[0].value + : pageData.scFragments[4].scContentFr.json[0].content[0].value} + </h2> + <p className="col-span-12 xl:col-span-8"> + {props.locale === "en" + ? pageData.scFragments[4].scContentEn.json[1].content[0].value + : pageData.scFragments[4].scContentFr.json[1].content[0].value} + </p> + <p className="col-span-12 xl:col-span-8"> + {props.locale === "en" + ? pageData.scFragments[4].scContentEn.json[2].content[0].value + : pageData.scFragments[4].scContentFr.json[2].content[0].value} + </p> + <ul className="list-disc col-span-12 xl:col-span-8"> + <li className="ml-10 text-[20px]"> + {props.locale === "en" + ? pageData.scFragments[4].scContentEn.json[3].content[0] + .content[0].value + : pageData.scFragments[4].scContentFr.json[3].content[0] + .content[0].value} + </li> + <li className="ml-10 text-[20px]"> + {props.locale === "en" + ? pageData.scFragments[4].scContentEn.json[3].content[1] + .content[0].value + : pageData.scFragments[4].scContentFr.json[3].content[1] + .content[0].value} + </li> + <li className="ml-10 text-[20px]"> + {props.locale === "en" + ? pageData.scFragments[4].scContentEn.json[3].content[2] + .content[0].value + : pageData.scFragments[4].scContentFr.json[3].content[2] + .content[0].value} + </li> + </ul> + <p className="col-span-12 xl:col-span-8"> + {props.locale === "en" + ? pageData.scFragments[4].scContentEn.json[4].content[0].value + : pageData.scFragments[4].scContentFr.json[4].content[0].value} + </p> + <div id="feature-section" className="col-span-12"> + <h2 className="col-span-12"> + {props.locale === "en" + ? pageData.scFragments[5].scContentEn.json[0].content[0].value + : pageData.scFragments[5].scContentFr.json[0].content[0] + .value} + </h2> + <div id="feature-1" className="grid grid-cols-12 gap-x-6 mb-9"> + <div className="mb-6 object-fill col-span-12 row-start-1 xl:row-start-1 xl:col-span-8"> + <Image + src={ + props.locale === "en" + ? pageData.scFragments[5].scFragments[0].scFragments[0] + .scImageEn._publishUrl + : pageData.scFragments[5].scFragments[0].scFragments[0] + .scImageFr._publishUrl + } + alt={ + props.locale === "en" + ? pageData.scFragments[5].scFragments[0].scFragments[0] + .scImageAltTextEn + : pageData.scFragments[5].scFragments[0].scFragments[0] + .scImageAltTextFr + } + height={ + pageData.scFragments[5].scFragments[0].scFragments[0] + .scImageEn.height + } + width={ + pageData.scFragments[5].scFragments[0].scFragments[0] + .scImageEn.width + } + sizes="100vw" + quality={100} + /> + </div> + <div className="col-span-12 row-start-3 xl:col-span-4 xl:row-start-1"> + <div className="py-4 pl-4 border-l-4 border-multi-blue-blue60f"> + <TextRender + data={ + props.locale === "en" + ? pageData.scFragments[5].scFragments[0].scContentEn + .json + : pageData.scFragments[5].scFragments[0].scContentFr + .json + } + /> + </div> + </div> + <div className="mb-6 col-span-12 xl:col-span-8 row-start-2 xl:row-start-2"> + <Collapse + id="image-text-collapse-1" + title={ + props.locale === "en" + ? pageData.scFragments[5].scFragments[0].scFragments[0] + .scLongDescHeadingEn + : pageData.scFragments[5].scFragments[0].scFragments[0] + .scLongDescHeadingFr + } + children={ + <TextRender + data={ + props.locale === "en" + ? pageData.scFragments[5].scFragments[0] + .scFragments[0].scLongDescEn.json + : pageData.scFragments[5].scFragments[0] + .scFragments[0].scLongDescFr.json + } + /> + } + /> + </div> + </div> + <div id="feature-2" className="grid grid-cols-12 gap-x-6 mb-9"> + <div className="mb-6 object-fill col-span-12 row-start-1 xl:row-start-1 xl:col-span-8"> + <Image + src={ + props.locale === "en" + ? pageData.scFragments[5].scFragments[1].scFragments[0] + .scImageEn._publishUrl + : pageData.scFragments[5].scFragments[1].scFragments[0] + .scImageFr._publishUrl + } + alt={ + props.locale === "en" + ? pageData.scFragments[5].scFragments[1].scFragments[0] + .scImageAltTextEn + : pageData.scFragments[5].scFragments[1].scFragments[0] + .scImageAltTextFr + } + height={ + pageData.scFragments[5].scFragments[1].scFragments[0] + .scImageEn.height + } + width={ + pageData.scFragments[5].scFragments[1].scFragments[0] + .scImageEn.width + } + sizes="100vw" + quality={100} + /> + </div> + <div className="col-span-12 row-start-3 xl:col-span-4 xl:row-start-1"> + <div className="p-4 border-l-4 border-multi-blue-blue60f"> + <TextRender + data={ + props.locale === "en" + ? pageData.scFragments[5].scFragments[1].scContentEn + .json + : pageData.scFragments[5].scFragments[1].scContentFr + .json + } + /> + </div> + </div> + <div className="mb-6 col-span-12 xl:col-span-8 row-start-2 xl:row-start-2"> + <Collapse + id="image-text-collapse-2" + title={ + props.locale === "en" + ? pageData.scFragments[5].scFragments[1].scFragments[0] + .scLongDescHeadingEn + : pageData.scFragments[5].scFragments[1].scFragments[0] + .scLongDescHeadingFr + } + children={ + <TextRender + data={ + props.locale === "en" + ? pageData.scFragments[5].scFragments[1] + .scFragments[0].scLongDescEn.json + : pageData.scFragments[5].scFragments[1] + .scFragments[0].scLongDescFr.json + } + /> + } + /> + </div> + </div> + <div id="feature-3" className="grid grid-cols-12 gap-x-6"> + <div className="mb-6 object-fill col-span-12 row-start-1 xl:row-start-1 xl:col-span-8"> + <Image + src={ + props.locale === "en" + ? pageData.scFragments[5].scFragments[2].scFragments[0] + .scImageEn._publishUrl + : pageData.scFragments[5].scFragments[2].scFragments[0] + .scImageFr._publishUrl + } + alt={ + props.locale === "en" + ? pageData.scFragments[5].scFragments[2].scFragments[0] + .scImageAltTextEn + : pageData.scFragments[5].scFragments[2].scFragments[0] + .scImageAltTextFr + } + height={ + pageData.scFragments[5].scFragments[2].scFragments[0] + .scImageEn.height + } + width={ + pageData.scFragments[5].scFragments[2].scFragments[0] + .scImageEn.width + } + sizes="100vw" + quality={100} + /> + </div> + <div className="col-span-12 row-start-3 xl:col-span-4 xl:row-start-1"> + <div className="p-4 border-l-4 border-multi-blue-blue60f"> + <TextRender + data={ + props.locale === "en" + ? pageData.scFragments[5].scFragments[2].scContentEn + .json + : pageData.scFragments[5].scFragments[2].scContentFr + .json + } + /> + </div> + </div> + <div className="mb-6 col-span-12 xl:col-span-8 row-start-2 xl:row-start-2"> + <Collapse + id="image-text-collapse-3" + title={ + props.locale === "en" + ? pageData.scFragments[5].scFragments[2].scFragments[0] + .scLongDescHeadingEn + : pageData.scFragments[5].scFragments[2].scFragments[0] + .scLongDescHeadingFr + } + children={ + <TextRender + data={ + props.locale === "en" + ? pageData.scFragments[5].scFragments[2] + .scFragments[0].scLongDescEn.json + : pageData.scFragments[5].scFragments[2] + .scFragments[0].scLongDescFr.json + } + /> + } + /> + </div> + </div> + </div> + </div> + + {updatesData.length === 0 ? null : ( + <section id="projectUpdates"> + <h2> + {props.locale === "en" + ? "Project updates" + : "Mises à jour du projet"} + </h2> + <ul className="grid lg:grid-cols-12 gap-x-4 lg:gap-y-12 list-none ml-0 mb-12"> + {displayProjectUpdates} + </ul> + </section> + )} + </div> + </Layout> + </> + ); +} + +export const getStaticProps = async ({ locale }) => { + // get page data from AEM + const { data: pageData } = await aemServiceInstance.getFragment( + "benefitsNavigatorQuery" + ); + // get dictionary + const { data: dictionary } = await aemServiceInstance.getFragment( + "dictionaryQuery" + ); + + return { + props: { + locale: locale, + adobeAnalyticsUrl: process.env.ADOBE_ANALYTICS_URL ?? null, + pageData: pageData.sclabsPageV1ByPath, + updatesData: pageData.sclabsPageV1ByPath.item.scLabProjectUpdates, + dictionary: dictionary.dictionaryV1List, + ...(await serverSideTranslations(locale, ["common"])), + }, + revalidate: process.env.ISR_ENABLED === "true" ? 10 : false, + }; +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import PageHead from "../../../components/fragment_renderer/PageHead"; +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; +import { Layout } from "../../../components/organisms/Layout"; +import { useEffect, useState } from "react"; +import aemServiceInstance from "../../../services/aemServiceInstance"; +import { getAllUpdateIds } from "../../../lib/utils/getAllUpdateIds"; +import { createBreadcrumbs } from "../../../lib/utils/createBreadcrumbs"; +import FragmentRender from "../../../components/fragment_renderer/FragmentRender"; +import { Heading } from "../../../components/molecules/Heading"; + +export default function MscaDashboardArticles(props) { + const [pageData] = useState(props.pageData); + const [dictionary] = useState(props.dictionary.items); + + useEffect(() => { + Iif (props.adobeAnalyticsUrl) { + window.adobeDataLayer = window.adobeDataLayer || []; + window.adobeDataLayer.push({ event: "pageLoad" }); + } + }, []); + + return ( + <> + <Layout + locale={props.locale} + langUrl={ + props.locale === "en" ? pageData.scPageNameFr : pageData.scPageNameEn + } + dateModifiedOverride={pageData.scDateModifiedOverwrite} + breadcrumbItems={createBreadcrumbs( + pageData.scBreadcrumbParentPages, + props.locale + )} + > + <PageHead pageData={pageData} locale={props.locale} /> + <section className="mb-12"> + <div className="layout-container"> + <Heading + tabIndex="-1" + id="pageMainTitle" + title={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + <div id="postedOnUpdatedOnSection" className="grid grid-cols-12"> + <p + className={`col-span-6 sm:col-span-4 ${ + props.locale === "en" ? "lg:col-span-2" : "lg:col-span-3" + } font-bold`} + > + {props.locale === "en" + ? dictionary[13].scTermEn + : dictionary[13].scTermFr} + </p> + <p className="col-span-6 col-start-7 sm:col-start-5 lg:col-span-2 md:col-start-5 mt-0"> + {pageData.scDateModifiedOverwrite} + </p> + <p + className={`row-start-2 col-span-6 sm:col-span-4 mt-0 ${ + props.locale === "en" ? "lg:col-span-2" : "lg:col-span-3" + } font-bold`} + > + {props.locale === "en" + ? dictionary[8].scTermEn + : dictionary[8].scTermFr} + </p> + <p className="row-start-2 col-span-6 col-start-7 sm:col-start-5 lg:col-span-2 md:col-start-5 mt-auto"> + {pageData.scDateModifiedOverwrite} + </p> + </div> + </div> + + {/* Main */} + <div id="mainContentSection"> + <FragmentRender + fragments={props.pageData.scFragments} + locale={props.locale} + /> + </div> + </section> + </Layout> + </> + ); +} + +export async function getStaticPaths() { + // Get pages data + const { data } = await aemServiceInstance.getFragment( + "getMSCADashboardArticles" + ); + // Get paths for dynamic routes from the page name data + const paths = getAllUpdateIds(data.sclabsPageV1List.items); + paths.map((path) => (path.params.id = path.params.id.split("/").at(-1))); + return { + paths, + fallback: "blocking", + }; +} + +export const getStaticProps = async ({ locale, params }) => { + // Get pages data + const { data } = await aemServiceInstance.getFragment( + "getMSCADashboardArticles" + ); + // get dictionary + const { data: dictionary } = await aemServiceInstance.getFragment( + "dictionaryQuery" + ); + const pages = data.sclabsPageV1List.items; + // Return page data that matches the current page being built + const pageData = pages.filter((page) => { + return ( + (locale === "en" ? page.scPageNameEn : page.scPageNameFr) + .split("/") + .at(-1) === params.id + ); + }); + + Iif (!pageData || !pageData.length) { + return { + notFound: true, + }; + } + + return { + props: { + locale: locale, + pageData: pageData[0], + dictionary: dictionary.dictionaryV1List, + adobeAnalyticsUrl: process.env.ADOBE_ANALYTICS_URL ?? null, + ...(await serverSideTranslations(locale, ["common", "vc"])), + }, + revalidate: process.env.ISR_ENABLED === "true" ? 10 : false, + }; +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ ++ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 | 1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x + +1x +2x +1x + +1x + +21x + + + + + +1x +1x + + + + + + + + + + + + + + + + + + + + + + + + + +1x +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + + + + + + + + + + | import Head from "next/head"; +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; +import { Layout } from "../../../components/organisms/Layout"; +import { useEffect } from "react"; +import aemServiceInstance from "../../../services/aemServiceInstance"; +import { ProjectInfo } from "../../../components/atoms/ProjectInfo"; +import { createBreadcrumbs } from "../../../lib/utils/createBreadcrumbs"; +import { Heading } from "../../../components/molecules/Heading"; +import { Collapse } from "../../../components/molecules/Collapse"; +import { ActionButton } from "../../../components/atoms/ActionButton"; +import Image from "next/image"; +import stageDictionary from "../../../lib/utils/stageDictionary"; +import TextRender from "../../../components/text_node_renderer/TextRender"; +import Card from "../../../components/molecules/Card"; +import FragmentRender from "../../../components/fragment_renderer/FragmentRender"; +import { sortUpdatesByDate } from "../../../lib/utils/sortUpdatesByDate"; + +export default function MscaDashboard(props) { + const pageData = props.pageData?.item; + const updatesData = sortUpdatesByDate(props.updatesData); + + const filteredDictionary = props.dictionary?.items?.filter( + (item) => + item.scId === "STARTED" || + item.scId === "ENDED" || + item.scId === "PROJECT-STAGE" || + item.scId === "SUMMARY" + ); + + const displayProjectUpdates = updatesData.map((update) => ( + <li key={update.scId} className="list-none ml-0 col-span-12 lg:col-span-4"> + <Card + showImage + imgSrc={ + props.locale === "en" + ? `https://www.canada.ca${update.scSocialMediaImageEn?._path}` + : `https://www.canada.ca${update.scSocialMediaImageFr?._path}` + } + imgAlt={ + props.locale === "en" + ? update.scSocialMediaImageAltTextEn + : update.scSocialMediaImageAltTextFr + } + imgHeight={update.scSocialMediaImageEn.height} + imgWidth={update.scSocialMediaImageEn.width} + title={props.locale === "en" ? update.scTitleEn : update.scTitleFr} + href={props.locale === "en" ? update.scPageNameEn : update.scPageNameFr} + description={`${ + props.locale === "en" + ? props.dictionary.items[13].scTermEn + : props.dictionary.items[13].scTermFr + } ${update.scDateModifiedOverwrite}`} + /> + </li> + )); + + useEffect(() => { + Iif (props.adobeAnalyticsUrl) { + window.adobeDataLayer = window.adobeDataLayer || []; + window.adobeDataLayer.push({ event: "pageLoad" }); + } + }, []); + + return ( + <> + <Layout + locale={props.locale} + langUrl={ + props.locale === "en" ? pageData.scPageNameFr : pageData.scPageNameEn + } + dateModifiedOverride={pageData.scDateModifiedOverwrite} + breadcrumbItems={createBreadcrumbs( + pageData.scBreadcrumbParentPages, + props.locale + )} + > + <Head> + {/* Primary HTML Meta Tags */} + <title> + {props.locale === "en" + ? `${pageData.scTitleEn} - Service Canada Labs` + : `${pageData.scTitleFr} - Laboratoires de Service Canada`} + </title> + <meta + name="description" + content={ + props.locale === "en" + ? pageData.scDescriptionEn.json[0].content[0].value + : pageData.scDescriptionFr.json[0].content[0].value + } + /> + <meta name="author" content="Service Canada" /> + <link rel="icon" href="/favicon.ico" /> + <link + rel="canonical" + href={ + "https://alpha.service.canada.ca" + + `${ + props.locale === "en" + ? pageData.scPageNameEn + : pageData.scPageNameFr + }` + } + /> + <link rel="schema.dcterms" href="http://purl.org/dc/terms/" /> + <meta + name="keywords" + content={ + props.locale === "en" + ? pageData.scKeywordsEn + : pageData.scKeywordsFr + } + /> + + {/* DCMI Meta Tags */} + <meta + name="dcterms.title" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + <meta + name="dcterms.language" + content={props.locale === "en" ? "eng" : "fra"} + title="ISO639-2/T" + /> + <meta + name="dcterms.creator" + content={ + props.locale === "en" + ? "Employment and Social Development Canada" + : "Emploi et Développement social Canada" + } + /> + <meta name="dcterms.accessRights" content="2" /> + <meta + name="dcterms.service" + content="ESDC-EDSC_SCLabs-LaboratoireSC" + /> + <meta name="dcterms.issued" title="W3CDTF" content="2021-07-20" /> + + <meta name="dcterms.modified" title="W3CDTF" content="2021-12-16" /> + <meta + name="dcterms.description" + content={ + props.locale === "en" + ? pageData.scDescriptionEn.json[0].content[0].value + : pageData.scDescriptionFr.json[0].content[0].value + } + /> + <meta + name="dcterms.subject" + title="gccore" + content={pageData.scSubject} + /> + <meta name="dcterms.spatial" content="Canada" /> + + {/* Open Graph / Facebook */} + <meta property="og:type" content="website" /> + <meta property="og:locale" content={props.locale} /> + <meta + property="og:url" + content={ + "https://alpha.service.canada.ca" + + `${ + props.locale === "en" + ? pageData.scPageNameEn + : pageData.scPageNameFr + }` + } + /> + <meta + property="og:title" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + <meta + property="og:description" + content={ + props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[0].content[0].value + : pageData.scFragments[0].scContentFr.json[0].content[0].value + } + /> + {/* <meta + property="og:image" + content={pageData.scSocialMediaImageEn._publishUrl} + /> */} + <meta + property="og:image:alt" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + + {/* Twitter */} + <meta property="twitter:card" content="summary_large_image" /> + <meta + property="twitter:url" + content={ + "https://alpha.service.canada.ca" + + `${ + props.locale === "en" + ? pageData.scPageNameEn + : pageData.scPageNameFr + }` + } + /> + <meta + property="twitter:title" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + <meta name="twitter:creator" content="Service Canada" /> + <meta + property="twitter:description" + content={ + props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[1].content[0].value + : pageData.scFragments[0].scContentFr.json[1].content[0].value + } + /> + {/* <meta + property="twitter:image" + content={pageData.scSocialMediaImageEn._publishUrl} + /> */} + <meta + property="twitter:image:alt" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + </Head> + + <div className="layout-container"> + <section aria-labelledby="pageMainTitle"> + <div className="flex flex-col break-words lg:grid lg:grid-cols-2"> + <div className="col-span-2"> + <Heading + tabIndex="-1" + id="pageMainTitle" + title={ + props.locale === "en" + ? pageData.scTitleEn + : pageData.scTitleFr + } + /> + </div> + <div className="hidden lg:grid row-span-2 row-start-2 col-start-2 p-0 mx-4"> + <div className="flex justify-center"> + <div className="object-fill h-auto w-auto max-w-450px"> + <Image + src={ + props.locale === "en" + ? pageData.scFragments[1].scImageEn._publishUrl + : pageData.scFragments[1].scImageFr._publishUrl + } + alt={ + (props.locale === "en" + ? pageData.scFragments[1].scImageAltTextEn + : pageData.scFragments[1].scImageAltTextFr) ?? "" + } + height={pageData.scFragments[1].scImageEn.height} + width={pageData.scFragments[1].scImageEn.width} + priority + sizes="33vw" + quality={100} + /> + </div> + </div> + </div> + <p className="row-start-2 font-body text-lg mb-4"> + {props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[1].content[0].value + : pageData.scFragments[0].scContentFr.json[1].content[0] + .value} + </p> + <div className="row-start-3"> + <ProjectInfo + locale={props.locale} + termStarted={ + props.locale === "en" + ? filteredDictionary[2].scTermEn + : filteredDictionary[2].scTermFr + } + termStage={ + props.locale === "en" + ? filteredDictionary[1].scTermEn + : filteredDictionary[1].scTermFr + } + termSummary={ + props.locale === "en" + ? filteredDictionary[3].scTermEn + : filteredDictionary[3].scTermFr + } + dateStarted={ + pageData.scFragments[0].scContentEn.json[2].content[0].value + } + term={ + props.locale === "en" + ? pageData.scFragments[2].scContentEn.json[0].content[0] + .value + : pageData.scFragments[2].scContentFr.json[0].content[0] + .value + } + definition={ + props.locale === "en" + ? pageData.scFragments[2].scContentEn.json[0].content[1] + .value + : pageData.scFragments[2].scContentFr.json[0].content[1] + .value + } + information={ + props.locale === "en" + ? pageData.scFragments[2].scTitleEn + : pageData.scFragments[2].scTitleFr + } + stage={ + props.locale === "en" + ? stageDictionary.en[pageData.scLabProjectStage] + : stageDictionary.fr[pageData.scLabProjectStage] + } + summary={ + props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[4].content[0] + .value + : pageData.scFragments[0].scContentFr.json[4].content[0] + .value + } + /> + </div> + </div> + </section> + </div> + <section id="pageMainContent"> + <FragmentRender + locale={props.locale} + fragments={pageData.scFragments.slice(3)} + excludeH1={true} + /> + </section> + {updatesData.length === 0 ? null : ( + <section id="projectUpdates" className="layout-container"> + <h2> + {props.locale === "en" + ? "Project updates" + : "Mises à jour du projet"} + </h2> + <ul className="grid lg:grid-cols-12 gap-x-4 lg:gap-y-12 list-none ml-0 mb-12"> + {displayProjectUpdates} + </ul> + </section> + )} + </Layout> + </> + ); +} + +export const getStaticProps = async ({ locale }) => { + // get page data from AEM + const { data: pageData } = await aemServiceInstance.getFragment( + "getMSCADashBoardPage" + ); + // get dictionary + const { data: dictionary } = await aemServiceInstance.getFragment( + "dictionaryQuery" + ); + + return { + props: { + locale: locale, + adobeAnalyticsUrl: process.env.ADOBE_ANALYTICS_URL ?? null, + pageData: pageData.sclabsPageV1ByPath, + updatesData: pageData.sclabsPageV1ByPath.item.scLabProjectUpdates, + dictionary: dictionary.dictionaryV1List, + ...(await serverSideTranslations(locale, ["common"])), + }, + revalidate: process.env.ISR_ENABLED === "true" ? 10 : false, + }; +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import { serverSideTranslations } from "next-i18next/serverSideTranslations"; +import { useTranslation } from "next-i18next"; +import PageHead from "../../../components/fragment_renderer/PageHead"; +import { Layout } from "../../../components/organisms/Layout"; +import { useEffect, useState } from "react"; +import aemServiceInstance from "../../../services/aemServiceInstance"; +import { getAllUpdateIds } from "../../../lib/utils/getAllUpdateIds"; +import { createBreadcrumbs } from "../../../lib/utils/createBreadcrumbs"; +import FragmentRender from "../../../components/fragment_renderer/FragmentRender"; +import { Heading } from "../../../components/molecules/Heading"; + +export default function DigitalStandardsArticles(props) { + const { t } = useTranslation("common"); + const [pageData] = useState(props.pageData); + const [dictionary] = useState(props.dictionary.items); + + useEffect(() => { + Iif (props.adobeAnalyticsUrl) { + window.adobeDataLayer = window.adobeDataLayer || []; + window.adobeDataLayer.push({ event: "pageLoad" }); + } + }, []); + + return ( + <> + <Layout + locale={props.locale} + langUrl={ + props.locale === "en" ? pageData.scPageNameFr : pageData.scPageNameEn + } + dateModifiedOverride={pageData.scDateModifiedOverwrite} + breadcrumbItems={createBreadcrumbs( + pageData.scBreadcrumbParentPages, + props.locale + )} + > + <PageHead pageData={pageData} locale={props.locale} /> + <section className="mb-12"> + <div className="layout-container"> + <Heading + tabIndex="-1" + id="pageMainTitle" + title={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + <div id="postedOnUpdatedOnSection" className="grid grid-cols-12"> + <p + className={`col-span-6 sm:col-span-4 ${ + props.locale === "en" ? "lg:col-span-2" : "lg:col-span-3" + } font-bold`} + > + {props.locale === "en" + ? dictionary[13].scTermEn + : dictionary[13].scTermFr} + </p> + <p className="col-span-6 col-start-7 sm:col-start-5 lg:col-span-2 md:col-start-5 mt-0"> + {pageData.scDateModifiedOverwrite} + </p> + <p + className={`row-start-2 col-span-6 sm:col-span-4 mt-0 ${ + props.locale === "en" ? "lg:col-span-2" : "lg:col-span-3" + } font-bold`} + > + {props.locale === "en" + ? dictionary[8].scTermEn + : dictionary[8].scTermFr} + </p> + <p className="row-start-2 col-span-6 col-start-7 sm:col-start-5 lg:col-span-2 md:col-start-5 mt-auto"> + {pageData.scDateModifiedOverwrite} + </p> + </div> + </div> + + {/* Main */} + <div id="mainContentSection"> + <FragmentRender + fragments={props.pageData.scFragments} + locale={props.locale} + /> + </div> + </section> + </Layout> + </> + ); +} + +export async function getStaticPaths() { + // Get pages data + const { data } = await aemServiceInstance.getFragment( + "getDigitalStandardsPlaybookArticles" + ); + // Get paths for dynamic routes from the page name data + const paths = getAllUpdateIds(data.sclabsPageV1List.items); + // Remove characters preceding the page name itself i.e. change "/en/projects/oas-benefits-estimator/what-we-learned" to "what-we-learned" + paths.map((path) => (path.params.id = path.params.id.split("/").at(-1))); + return { + paths, + fallback: "blocking", + }; +} + +export const getStaticProps = async ({ locale, params }) => { + // Get pages data + const { data } = await aemServiceInstance.getFragment( + "getDigitalStandardsPlaybookArticles" + ); + // get dictionary + const { data: dictionary } = await aemServiceInstance.getFragment( + "dictionaryQuery" + ); + const pages = data.sclabsPageV1List.items; + // Return page data that matches the current page being built + const pageData = pages.filter((page) => { + return ( + (locale === "en" ? page.scPageNameEn : page.scPageNameFr) + .split("/") + .at(-1) === params.id + ); + }); + + Iif (!pageData || !pageData.length) { + return { + notFound: true, + }; + } + + return { + props: { + locale: locale, + pageData: pageData[0], + dictionary: dictionary.dictionaryV1List, + adobeAnalyticsUrl: process.env.ADOBE_ANALYTICS_URL ?? null, + ...(await serverSideTranslations(locale, ["common"])), + }, + revalidate: process.env.ISR_ENABLED === "true" ? 10 : false, + }; +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ ++ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 +484 +485 | 1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x + +1x +2x +1x + +1x + +21x + + + + + +1x +1x + + + + + + + + + + + + + + + + + + + + + + + + + +1x +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + + + + + + + + + + | import Head from "next/head"; +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; +import { Layout } from "../../../components/organisms/Layout"; +import { useEffect, useState } from "react"; +import aemServiceInstance from "../../../services/aemServiceInstance"; +import { ProjectInfo } from "../../../components/atoms/ProjectInfo"; +import Card from "../../../components/molecules/Card"; +import { createBreadcrumbs } from "../../../lib/utils/createBreadcrumbs"; +import { Heading } from "../../../components/molecules/Heading"; +import { ActionButton } from "../../../components/atoms/ActionButton"; +import Image from "next/image"; +import stageDictionary from "../../../lib/utils/stageDictionary"; +import { sortUpdatesByDate } from "../../../lib/utils/sortUpdatesByDate"; + +export default function DigitalStandardsPlaybookPage(props) { + const [pageData] = useState(props.pageData.item); + const updatesData = sortUpdatesByDate(props.updatesData); + + const filteredDictionary = props.dictionary?.items?.filter( + (item) => + item.scId === "STARTED" || + item.scId === "ENDED" || + item.scId === "PROJECT-STAGE" || + item.scId === "SUMMARY" + ); + + const displayProjectUpdates = updatesData.map((update) => ( + <li key={update.scId} className="list-none ml-0 col-span-12 lg:col-span-4"> + <Card + showImage + imgSrc={ + props.locale === "en" + ? `https://www.canada.ca${update.scSocialMediaImageEn?._path}` + : `https://www.canada.ca${update.scSocialMediaImageFr?._path}` + } + imgAlt={ + props.locale === "en" + ? update.scSocialMediaImageAltTextEn + : update.scSocialMediaImageAltTextFr + } + imgHeight={update.scSocialMediaImageEn.height} + imgWidth={update.scSocialMediaImageEn.width} + title={props.locale === "en" ? update.scTitleEn : update.scTitleFr} + href={props.locale === "en" ? update.scPageNameEn : update.scPageNameFr} + description={`${ + props.locale === "en" + ? props.dictionary.items[13].scTermEn + : props.dictionary.items[13].scTermFr + } ${update.scDateModifiedOverwrite}`} + /> + </li> + )); + + useEffect(() => { + Iif (props.adobeAnalyticsUrl) { + window.adobeDataLayer = window.adobeDataLayer || []; + window.adobeDataLayer.push({ event: "pageLoad" }); + } + }, []); + + return ( + <> + <Layout + locale={props.locale} + langUrl={ + props.locale === "en" ? pageData.scPageNameFr : pageData.scPageNameEn + } + dateModifiedOverride={pageData.scDateModifiedOverwrite ?? "2023-11-24"} + breadcrumbItems={createBreadcrumbs( + pageData.scBreadcrumbParentPages, + props.locale + )} + > + <Head> + {/* Primary HTML Meta Tags */} + <title> + {props.locale === "en" + ? `${pageData.scTitleEn} - Service Canada Labs` + : `${pageData.scTitleFr} - Laboratoires de Service Canada`} + </title> + <meta + name="description" + content={ + props.locale === "en" + ? pageData.scDescriptionEn.json[0].content[0].value + : pageData.scDescriptionFr.json[0].content[0].value + } + /> + <meta name="author" content="Service Canada" /> + <link rel="icon" href="/favicon.ico" /> + <link + rel="canonical" + href={ + "https://alpha.service.canada.ca" + + `${ + props.locale === "en" + ? pageData.scPageNameEn + : pageData.scPageNameFr + }` + } + /> + <link rel="schema.dcterms" href="http://purl.org/dc/terms/" /> + <meta + name="keywords" + content={ + props.locale === "en" + ? pageData.scKeywordsEn + : pageData.scKeywordsFr + } + /> + + {/* DCMI Meta Tags */} + <meta + name="dcterms.title" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + <meta + name="dcterms.language" + content={props.locale === "en" ? "eng" : "fra"} + title="ISO639-2/T" + /> + <meta + name="dcterms.creator" + content={ + props.locale === "en" + ? "Employment and Social Development Canada" + : "Emploi et Développement social Canada" + } + /> + <meta name="dcterms.accessRights" content="2" /> + <meta + name="dcterms.service" + content="ESDC-EDSC_SCLabs-LaboratoireSC" + /> + <meta name="dcterms.issued" title="W3CDTF" content="2021-07-20" /> + + <meta name="dcterms.modified" title="W3CDTF" content="2021-12-16" /> + <meta + name="dcterms.description" + content={ + props.locale === "en" + ? pageData.scDescriptionEn.json[0].content[0].value + : pageData.scDescriptionFr.json[0].content[0].value + } + /> + <meta + name="dcterms.subject" + title="gccore" + content={pageData.scSubject} + /> + <meta name="dcterms.spatial" content="Canada" /> + + {/* Open Graph / Facebook */} + <meta property="og:type" content="website" /> + <meta property="og:locale" content={props.locale} /> + <meta + property="og:url" + content={ + "https://alpha.service.canada.ca" + + `${ + props.locale === "en" + ? pageData.scPageNameEn + : pageData.scPageNameFr + }` + } + /> + <meta + property="og:title" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + <meta + property="og:description" + content={ + props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[0].content[0].value + : pageData.scFragments[0].scContentFr.json[0].content[0].value + } + /> + <meta + property="og:image" + content={pageData.scSocialMediaImageEn._publishUrl} + /> + <meta + property="og:image:alt" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + + {/* Twitter */} + <meta property="twitter:card" content="summary_large_image" /> + <meta + property="twitter:url" + content={ + "https://alpha.service.canada.ca" + + `${ + props.locale === "en" + ? pageData.scPageNameEn + : pageData.scPageNameFr + }` + } + /> + <meta + property="twitter:title" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + <meta name="twitter:creator" content="Service Canada" /> + <meta + property="twitter:description" + content={ + props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[1].content[0].value + : pageData.scFragments[0].scContentFr.json[1].content[0].value + } + /> + <meta + property="twitter:image" + content={pageData.scSocialMediaImageEn._publishUrl} + /> + <meta + property="twitter:image:alt" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + </Head> + + <div className="layout-container"> + <section aria-labelledby="pageMainTitle"> + <div className="flex flex-col break-words lg:grid lg:grid-cols-2"> + <div className="col-span-2"> + <Heading + tabIndex="-1" + id="pageMainTitle" + title={ + props.locale === "en" + ? pageData.scTitleEn + : pageData.scTitleFr + } + /> + </div> + <div className="hidden lg:grid row-span-2 row-start-2 col-start-2 p-0 mx-4"> + <div className="flex justify-center"> + <div className="object-fill h-auto w-auto max-w-450px"> + <Image + src={ + props.locale === "en" + ? pageData.scFragments[2].scImageEn._publishUrl + : pageData.scFragments[2].scImageFr._publishUrl + } + alt={ + (props.locale === "en" + ? pageData.scFragments[2].scImageAltTextEn + : pageData.scFragments[2].scImageAltTextFr) ?? "" + } + height={pageData.scFragments[2].scImageEn.height} + width={pageData.scFragments[2].scImageEn.width} + priority + sizes="33vw" + quality={100} + /> + </div> + </div> + </div> + <p className="row-start-2 font-body text-lg mb-4"> + {props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[1].content[0].value + : pageData.scFragments[0].scContentFr.json[1].content[0] + .value} + </p> + <div className="row-start-3"> + <ProjectInfo + locale={props.locale} + termStarted={ + props.locale === "en" + ? filteredDictionary[2].scTermEn + : filteredDictionary[2].scTermFr + } + termStage={ + props.locale === "en" + ? filteredDictionary[1].scTermEn + : filteredDictionary[1].scTermFr + } + termSummary={ + props.locale === "en" + ? filteredDictionary[3].scTermEn + : filteredDictionary[3].scTermFr + } + dateStarted={ + pageData.scFragments[0].scContentEn.json[2].content[0].value + } + term={ + props.locale === "en" + ? pageData.scFragments[1].scContentEn.json[0].content[0] + .value + : pageData.scFragments[1].scContentFr.json[0].content[0] + .value + } + definition={ + props.locale === "en" + ? pageData.scFragments[1].scContentEn.json[0].content[1] + .value + : pageData.scFragments[1].scContentFr.json[0].content[1] + .value + } + information={ + props.locale === "en" + ? pageData.scFragments[2].scTitleEn + : pageData.scFragments[2].scTitleFr + } + stage={ + props.locale === "en" + ? stageDictionary.en[pageData.scLabProjectStage] + : stageDictionary.fr[pageData.scLabProjectStage] + } + summary={ + props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[4].content[0] + .value + : pageData.scFragments[0].scContentFr.json[4].content[0] + .value + } + /> + </div> + </div> + </section> + <section id="pageMainContent"> + <div className="grid grid-cols-12"> + <h2 className="col-span-12"> + {props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[5].content[0].value + : pageData.scFragments[0].scContentFr.json[5].content[0] + .value} + </h2> + <p className="col-span-12 xl:col-span-8"> + {props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[6].content[0].value + : pageData.scFragments[0].scContentFr.json[6].content[0] + .value} + </p> + <p className="col-span-12 xl:col-span-8"> + {props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[7].content[0].value + : pageData.scFragments[0].scContentFr.json[7].content[0] + .value} + </p> + + <h2 className="col-span-12"> + {props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[8].content[0].value + : pageData.scFragments[0].scContentFr.json[8].content[0] + .value} + </h2> + <p className="col-span-12 xl:col-span-8"> + {props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[9].content[0].value + : pageData.scFragments[0].scContentFr.json[9].content[0] + .value} + <a + className="underline underline-offset-[6px]" + href={ + props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[9].content[1] + .data.href + : pageData.scFragments[0].scContentFr.json[9].content[1] + .data.href + } + > + {props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[9].content[1] + .value + : pageData.scFragments[0].scContentFr.json[9].content[1] + .value} + </a> + {props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[9].content[2].value + : pageData.scFragments[0].scContentFr.json[9].content[2] + .value} + </p> + <p className="col-span-12 xl:col-span-8"> + {props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[10].content[0] + .value + : pageData.scFragments[0].scContentFr.json[10].content[0] + .value} + </p> + + <ActionButton + id="take-survey" + style="primary" + custom="col-span-12 my-6" + href={ + props.locale === "en" + ? pageData.scFragments[3].scDestinationURLEn + : pageData.scFragments[3].scDestinationURLFr + } + text={ + props.locale === "en" + ? pageData.scFragments[3].scTitleEn + : pageData.scFragments[3].scTitleFr + } + ariaExpanded={props.ariaExpanded} + /> + + <p className="col-span-12 xl:col-span-8"> + {props.locale === "en" + ? pageData.scFragments[4].scContentEn.json[0].content[0].value + : pageData.scFragments[4].scContentFr.json[0].content[0] + .value} + <a + className="underline underline-offset-[6px]" + href={ + props.locale === "en" + ? pageData.scFragments[4].scContentEn.json[0].content[1] + .data.href + : pageData.scFragments[4].scContentFr.json[0].content[1] + .data.href + } + > + {props.locale === "en" + ? pageData.scFragments[4].scContentEn.json[0].content[1] + .value + : pageData.scFragments[4].scContentFr.json[0].content[1] + .value} + </a> + {props.locale === "en" + ? pageData.scFragments[4].scContentEn.json[0].content[2].value + : pageData.scFragments[4].scContentFr.json[0].content[2] + .value} + </p> + <p className="col-span-12 xl:col-span-8"> + {props.locale === "en" + ? pageData.scFragments[4].scContentEn.json[1].content[0].value + : pageData.scFragments[4].scContentFr.json[1].content[0] + .value} + </p> + </div> + </section> + {updatesData.length === 0 ? null : ( + <section id="projectUpdates"> + <h2> + {props.locale === "en" + ? "Project updates" + : "Mises à jour du projet"} + </h2> + <ul className="grid lg:grid-cols-12 gap-x-4 lg:gap-y-12 list-none ml-0 mb-12"> + {displayProjectUpdates} + </ul> + </section> + )} + </div> + </Layout> + </> + ); +} + +export const getStaticProps = async ({ locale }) => { + // get page data from AEM + const { data: pageData } = await aemServiceInstance.getFragment( + "getDigitalStandardsPlaybookPage" + ); + // get dictionary + const { data: dictionary } = await aemServiceInstance.getFragment( + "dictionaryQuery" + ); + + return { + props: { + locale: locale, + adobeAnalyticsUrl: process.env.ADOBE_ANALYTICS_URL ?? null, + pageData: pageData.sclabsPageV1ByPath, + updatesData: pageData.sclabsPageV1ByPath.item.scLabProjectUpdates, + dictionary: dictionary.dictionaryV1List, + ...(await serverSideTranslations(locale, ["common"])), + }, + revalidate: process.env.ISR_ENABLED === "true" ? 10 : false, + }; +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import { serverSideTranslations } from "next-i18next/serverSideTranslations"; +import { useTranslation } from "next-i18next"; +import PageHead from "../../../components/fragment_renderer/PageHead"; +import { Layout } from "../../../components/organisms/Layout"; +import { useEffect, useState } from "react"; +import aemServiceInstance from "../../../services/aemServiceInstance"; +import { getAllUpdateIds } from "../../../lib/utils/getAllUpdateIds"; +import { createBreadcrumbs } from "../../../lib/utils/createBreadcrumbs"; +import FragmentRender from "../../../components/fragment_renderer/FragmentRender"; +import { Heading } from "../../../components/molecules/Heading"; + +export default function IntegratedChannelStrategyArticles(props) { + const { t } = useTranslation("common"); + const [pageData] = useState(props.pageData); + const [dictionary] = useState(props.dictionary.items); + + useEffect(() => { + Iif (props.adobeAnalyticsUrl) { + window.adobeDataLayer = window.adobeDataLayer || []; + window.adobeDataLayer.push({ event: "pageLoad" }); + } + }, []); + + return ( + <> + <Layout + locale={props.locale} + langUrl={ + props.locale === "en" ? pageData.scPageNameFr : pageData.scPageNameEn + } + dateModifiedOverride={pageData.scDateModifiedOverwrite} + breadcrumbItems={createBreadcrumbs( + pageData.scBreadcrumbParentPages, + props.locale + )} + > + <PageHead pageData={pageData} locale={props.locale} /> + <section className="mb-12"> + <div className="layout-container"> + <Heading + tabIndex="-1" + id="pageMainTitle" + title={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + <div id="postedOnUpdatedOnSection" className="grid grid-cols-12"> + <p + className={`col-span-6 sm:col-span-4 ${ + props.locale === "en" ? "lg:col-span-2" : "lg:col-span-3" + } font-bold`} + > + {props.locale === "en" + ? dictionary[13].scTermEn + : dictionary[13].scTermFr} + </p> + <p className="col-span-6 col-start-7 sm:col-start-5 lg:col-span-2 md:col-start-5 mt-0"> + {pageData.scDateModifiedOverwrite} + </p> + <p + className={`row-start-2 col-span-6 sm:col-span-4 mt-0 ${ + props.locale === "en" ? "lg:col-span-2" : "lg:col-span-3" + } font-bold`} + > + {props.locale === "en" + ? dictionary[8].scTermEn + : dictionary[8].scTermFr} + </p> + <p className="row-start-2 col-span-6 col-start-7 sm:col-start-5 lg:col-span-2 md:col-start-5 mt-auto"> + {pageData.scDateModifiedOverwrite} + </p> + </div> + </div> + + {/* Main */} + <div id="mainContentSection"> + <FragmentRender + fragments={props.pageData.scFragments} + locale={props.locale} + /> + </div> + </section> + </Layout> + </> + ); +} + +export async function getStaticPaths() { + // Get pages data + const { data } = await aemServiceInstance.getFragment( + "integratedChannelStrategyArticlesQuery" + ); + // Get paths for dynamic routes from the page name data + const paths = getAllUpdateIds(data.sclabsPageV1List.items); + // Remove characters preceding the page name itself i.e. change "/en/projects/oas-benefits-estimator/what-we-learned" to "what-we-learned" + paths.map((path) => (path.params.id = path.params.id.split("/").at(-1))); + return { + paths, + fallback: "blocking", + }; +} + +export const getStaticProps = async ({ locale, params }) => { + // Get pages data + const { data } = await aemServiceInstance.getFragment( + "integratedChannelStrategyArticlesQuery" + ); + // get dictionary + const { data: dictionary } = await aemServiceInstance.getFragment( + "dictionaryQuery" + ); + const pages = data.sclabsPageV1List.items; + // Return page data that matches the current page being built + const pageData = pages.filter((page) => { + return ( + (locale === "en" ? page.scPageNameEn : page.scPageNameFr) + .split("/") + .at(-1) === params.id + ); + }); + + Iif (!pageData || !pageData.length) { + return { + notFound: true, + }; + } + + return { + props: { + locale: locale, + pageData: pageData[0], + dictionary: dictionary.dictionaryV1List, + adobeAnalyticsUrl: process.env.ADOBE_ANALYTICS_URL ?? null, + ...(await serverSideTranslations(locale, ["common"])), + }, + revalidate: process.env.ISR_ENABLED === "true" ? 10 : false, + }; +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ ++ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 | 1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x + +1x +2x +1x +1x + + +21x + + + + + + +1x + + + + + + + + + + + + + + + + + + + + + + + + + + +1x +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + + + + + + + + + + | import Head from "next/head"; +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; +import { Layout } from "../../../components/organisms/Layout"; +import { ActionButton } from "../../../components//atoms/ActionButton"; +import { useEffect, useState } from "react"; +import aemServiceInstance from "../../../services/aemServiceInstance"; +import { ProjectInfo } from "../../../components/atoms/ProjectInfo"; +import Card from "../../../components/molecules/Card"; +import { createBreadcrumbs } from "../../../lib/utils/createBreadcrumbs"; +import { Heading } from "../../../components/molecules/Heading"; +import TextRender from "../../../components/text_node_renderer/TextRender"; +import Image from "next/image"; +import stageDictionary from "../../../lib/utils/stageDictionary"; +import { sortUpdatesByDate } from "../../../lib/utils/sortUpdatesByDate"; + +export default function IntegratedChannelStrategyPage(props) { + const [pageData] = useState(props.pageData.item); + const updatesData = sortUpdatesByDate(props.updatesData); + const [filteredDictionary] = useState( + props.dictionary.items.filter( + (item) => + item.scId === "STARTED" || + item.scId === "ENDED" || + item.scId === "PROJECT-STAGE" || + item.scId === "SUMMARY" + ) + ); + + const displayProjectUpdates = updatesData.map((update) => ( + <li key={update.scId} className="list-none ml-0 col-span-12 lg:col-span-4"> + <Card + showImage + imgSrc={ + props.locale === "en" + ? `https://www.canada.ca${update.scSocialMediaImageEn._path}` + : `https://www.canada.ca${update.scSocialMediaImageFr._path}` + } + imgAlt={ + (props.locale === "en" + ? update.scSocialMediaImageAltTextEn + : update.scSocialMediaImageAltTextFr) ?? "" + } + imgHeight={update.scSocialMediaImageEn.height} + imgWidth={update.scSocialMediaImageEn.width} + title={props.locale === "en" ? update.scTitleEn : update.scTitleFr} + href={props.locale === "en" ? update.scPageNameEn : update.scPageNameFr} + description={`${ + props.locale === "en" + ? props.dictionary.items[13].scTermEn + : props.dictionary.items[13].scTermFr + } ${update.scDateModifiedOverwrite}`} + /> + </li> + )); + + useEffect(() => { + Iif (props.adobeAnalyticsUrl) { + window.adobeDataLayer = window.adobeDataLayer || []; + window.adobeDataLayer.push({ event: "pageLoad" }); + } + }, []); + + return ( + <> + <Layout + locale={props.locale} + langUrl={ + props.locale === "en" ? pageData.scPageNameFr : pageData.scPageNameEn + } + dateModifiedOverride={pageData.scDateModifiedOverwrite} + breadcrumbItems={createBreadcrumbs( + pageData.scBreadcrumbParentPages, + props.locale + )} + > + <Head> + {/* Primary HTML Meta Tags */} + <title> + {props.locale === "en" + ? `${pageData.scTitleEn} - Service Canada Labs` + : `${pageData.scTitleFr} - Laboratoires de Service Canada`} + </title> + <meta + name="description" + content={ + props.locale === "en" + ? pageData.scDescriptionEn.json[0].content[0].value + : pageData.scDescriptionFr.json[0].content[0].value + } + /> + <meta name="author" content="Service Canada" /> + <link rel="icon" href="/favicon.ico" /> + <link + rel="canonical" + href={ + "https://alpha.service.canada.ca" + + `${ + props.locale === "en" + ? pageData.scPageNameEn + : pageData.scPageNameFr + }` + } + /> + <link rel="schema.dcterms" href="http://purl.org/dc/terms/" /> + <meta + name="keywords" + content={ + props.locale === "en" + ? pageData.scKeywordsEn + : pageData.scKeywordsFr + } + /> + + {/* DCMI Meta Tags */} + <meta + name="dcterms.title" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + <meta + name="dcterms.language" + content={props.locale === "en" ? "eng" : "fra"} + title="ISO639-2/T" + /> + <meta + name="dcterms.creator" + content={ + props.locale === "en" + ? "Employment and Social Development Canada" + : "Emploi et Développement social Canada" + } + /> + <meta name="dcterms.accessRights" content="2" /> + <meta + name="dcterms.service" + content="ESDC-EDSC_SCLabs-LaboratoireSC" + /> + <meta name="dcterms.issued" title="W3CDTF" content="2021-07-20" /> + + <meta name="dcterms.modified" title="W3CDTF" content="2021-12-16" /> + <meta + name="dcterms.description" + content={ + props.locale === "en" + ? pageData.scDescriptionEn.json[0].content[0].value + : pageData.scDescriptionFr.json[0].content[0].value + } + /> + <meta + name="dcterms.subject" + title="gccore" + content={pageData.scSubject} + /> + <meta name="dcterms.spatial" content="Canada" /> + + {/* Open Graph / Facebook */} + <meta property="og:type" content="website" /> + <meta property="og:locale" content={props.locale} /> + <meta + property="og:url" + content={ + "https://alpha.service.canada.ca" + + `${ + props.locale === "en" + ? pageData.scPageNameEn + : pageData.scPageNameFr + }` + } + /> + <meta + property="og:title" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + <meta + property="og:description" + content={ + props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[0].content[0].value + : pageData.scFragments[0].scContentFr.json[0].content[0].value + } + /> + <meta + property="og:image" + content={pageData.scSocialMediaImageEn._publishUrl} + /> + <meta + property="og:image:alt" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + + {/* Twitter */} + <meta property="twitter:card" content="summary_large_image" /> + <meta + property="twitter:url" + content={ + "https://alpha.service.canada.ca" + + `${ + props.locale === "en" + ? pageData.scPageNameEn + : pageData.scPageNameFr + }` + } + /> + <meta + property="twitter:title" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + <meta name="twitter:creator" content="Service Canada" /> + <meta + property="twitter:description" + content={ + props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[1].content[0].value + : pageData.scFragments[0].scContentFr.json[1].content[0].value + } + /> + <meta + property="twitter:image" + content={pageData.scSocialMediaImageEn._publishUrl} + /> + <meta + property="twitter:image:alt" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + </Head> + + <div className="layout-container"> + <section aria-labelledby="pageMainTitle"> + <div className="flex flex-col break-words lg:grid lg:grid-cols-2"> + <div className="col-span-2"> + <Heading + tabIndex="-1" + id="pageMainTitle" + title={ + props.locale === "en" + ? pageData.scTitleEn + : pageData.scTitleFr + } + /> + </div> + <div className="hidden lg:grid row-span-2 row-start-2 col-start-2 p-0 mx-4"> + <div className="flex justify-center"> + <div className="object-fill h-auto w-auto max-w-450px"> + <Image + src={ + props.locale === "en" + ? pageData.scFragments[2].scImageEn._publishUrl + : pageData.scFragments[2].scImageFr._publishUrl + } + alt={ + (props.locale === "en" + ? pageData.scFragments[2].scImageAltTextEn + : pageData.scFragments[2].scImageAltTextFr) ?? "" + } + height={pageData.scFragments[2].scImageEn.height} + width={pageData.scFragments[2].scImageEn.width} + priority + sizes="33vw" + quality={100} + /> + </div> + </div> + </div> + <p className="row-start-2 font-body text-lg mb-4"> + {props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[1].content[0].value + : pageData.scFragments[0].scContentFr.json[1].content[0] + .value} + </p> + <div className="row-start-3"> + <ProjectInfo + locale={props.locale} + termStarted={ + props.locale === "en" + ? filteredDictionary[2].scTermEn + : filteredDictionary[2].scTermFr + } + termStage={ + props.locale === "en" + ? filteredDictionary[1].scTermEn + : filteredDictionary[1].scTermFr + } + termSummary={ + props.locale === "en" + ? filteredDictionary[3].scTermEn + : filteredDictionary[3].scTermFr + } + dateStarted={ + pageData.scFragments[0].scContentEn.json[2].content[0].value + } + term={ + props.locale === "en" + ? pageData.scFragments[1].scContentEn.json[0].content[0] + .value + : pageData.scFragments[1].scContentFr.json[0].content[0] + .value + } + definition={ + props.locale === "en" + ? pageData.scFragments[1].scContentEn.json[0].content[1] + .value + : pageData.scFragments[1].scContentFr.json[0].content[1] + .value + } + information={ + props.locale === "en" + ? pageData.scFragments[2].scTitleEn + : pageData.scFragments[2].scTitleFr + } + stage={ + props.locale === "en" + ? stageDictionary.en[pageData.scLabProjectStage] + : stageDictionary.fr[pageData.scLabProjectStage] + } + summary={ + props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[4].content[0] + .value + : pageData.scFragments[0].scContentFr.json[4].content[0] + .value + } + /> + </div> + </div> + </section> + <div id="pageMainContent" className="grid grid-cols-12"> + <div className="col-span-12 lg:col-span-7 mt-[48px]"> + <TextRender + data={ + props.locale === "en" + ? pageData.scFragments[0].scContentEn.json.slice(5) + : pageData.scFragments[0].scContentFr.json.slice(5) + } + excludeH1={true} + /> + </div> + </div> + {updatesData.length === 0 ? null : ( + <section id="projectUpdates"> + <h2> + {props.locale === "en" + ? "Project updates" + : "Mises à jour du projet"} + </h2> + <ul className="grid lg:grid-cols-12 gap-x-4 lg:gap-y-12 list-none ml-0 mb-12"> + {displayProjectUpdates} + </ul> + </section> + )} + </div> + </Layout> + </> + ); +} + +export const getStaticProps = async ({ locale }) => { + // get page data from AEM + const { data: pageData } = await aemServiceInstance.getFragment( + "integratedChannelStrategyQuery" + ); + // get dictionary + const { data: dictionary } = await aemServiceInstance.getFragment( + "dictionaryQuery" + ); + + return { + props: { + locale: locale, + adobeAnalyticsUrl: process.env.ADOBE_ANALYTICS_URL ?? null, + pageData: pageData.sclabsPageV1ByPath, + updatesData: pageData.sclabsPageV1ByPath.item.scLabProjectUpdates, + dictionary: dictionary.dictionaryV1List, + ...(await serverSideTranslations(locale, ["common"])), + }, + revalidate: process.env.ISR_ENABLED === "true" ? 10 : false, + }; +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | import { serverSideTranslations } from "next-i18next/serverSideTranslations"; +import { useTranslation } from "next-i18next"; +import PageHead from "../../../components/fragment_renderer/PageHead"; +import { Layout } from "../../../components/organisms/Layout"; +import { useEffect, useState } from "react"; +import aemServiceInstance from "../../../services/aemServiceInstance"; +import { getAllUpdateIds } from "../../../lib/utils/getAllUpdateIds"; +import { createBreadcrumbs } from "../../../lib/utils/createBreadcrumbs"; +import FragmentRender from "../../../components/fragment_renderer/FragmentRender"; +import { Heading } from "../../../components/molecules/Heading"; + +export default function OASBenefitsEstimatorArticles(props) { + const { t } = useTranslation("common"); + const [pageData] = useState(props.pageData); + const [dictionary] = useState(props.dictionary.items); + + useEffect(() => { + Iif (props.adobeAnalyticsUrl) { + window.adobeDataLayer = window.adobeDataLayer || []; + window.adobeDataLayer.push({ event: "pageLoad" }); + } + }, []); + + return ( + <> + <Layout + locale={props.locale} + langUrl={ + props.locale === "en" ? pageData.scPageNameFr : pageData.scPageNameEn + } + dateModifiedOverride={pageData.scDateModifiedOverwrite} + breadcrumbItems={createBreadcrumbs( + pageData.scBreadcrumbParentPages, + props.locale + )} + > + <PageHead pageData={pageData} locale={props.locale} /> + <section className="mb-12"> + <div className="layout-container"> + <Heading + tabIndex="-1" + id="pageMainTitle" + title={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + <div id="postedOnUpdatedOnSection" className="grid grid-cols-12"> + <p + className={`col-span-6 sm:col-span-4 ${ + props.locale === "en" ? "lg:col-span-2" : "lg:col-span-3" + } font-bold`} + > + {props.locale === "en" + ? dictionary[13].scTermEn + : dictionary[13].scTermFr} + </p> + <p className="col-span-6 col-start-7 sm:col-start-5 lg:col-span-2 md:col-start-5 mt-0"> + {pageData.scDateModifiedOverwrite} + </p> + <p + className={`row-start-2 col-span-6 sm:col-span-4 mt-0 ${ + props.locale === "en" ? "lg:col-span-2" : "lg:col-span-3" + } font-bold`} + > + {props.locale === "en" + ? dictionary[8].scTermEn + : dictionary[8].scTermFr} + </p> + <p className="row-start-2 col-span-6 col-start-7 sm:col-start-5 lg:col-span-2 md:col-start-5 mt-auto"> + {pageData.scDateModifiedOverwrite} + </p> + </div> + </div> + + {/* Main */} + <div id="mainContentSection"> + <FragmentRender + fragments={props.pageData.scFragments} + locale={props.locale} + /> + </div> + </section> + </Layout> + </> + ); +} + +export async function getStaticPaths() { + // Get pages data + const { data } = await aemServiceInstance.getFragment( + "oasBenefitsEstimatorArticlesQuery" + ); + // Get paths for dynamic routes from the page name data + const paths = getAllUpdateIds(data.sclabsPageV1List.items); + // Remove characters preceding the page name itself i.e. change "/en/projects/oas-benefits-estimator/what-we-learned" to "what-we-learned" + paths.map((path) => (path.params.id = path.params.id.split("/").at(-1))); + return { + paths, + fallback: "blocking", + }; +} + +export const getStaticProps = async ({ locale, params }) => { + // Get pages data + const { data } = await aemServiceInstance.getFragment( + "oasBenefitsEstimatorArticlesQuery" + ); + // get dictionary + const { data: dictionary } = await aemServiceInstance.getFragment( + "dictionaryQuery" + ); + const pages = data.sclabsPageV1List.items; + // Return page data that matches the current page being built + const pageData = pages.filter((page) => { + return ( + (locale === "en" ? page.scPageNameEn : page.scPageNameFr) + .split("/") + .at(-1) === params.id + ); + }); + + Iif (!pageData || !pageData.length) { + return { + notFound: true, + }; + } + + return { + props: { + locale: locale, + pageData: pageData[0], + dictionary: dictionary.dictionaryV1List, + adobeAnalyticsUrl: process.env.ADOBE_ANALYTICS_URL ?? null, + ...(await serverSideTranslations(locale, ["common"])), + }, + revalidate: process.env.ISR_ENABLED === "true" ? 10 : false, + }; +}; + |
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ ++ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 | 1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x + +1x +2x +1x +1x + + +21x + + + + + + +1x +2x + + + + + + + + + + + + + + + + + + + + + + + + + +1x +1x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1x + + + + + + + + + + + + + + + + + + + + + + | import Head from "next/head"; +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; +import { Layout } from "../../../components/organisms/Layout"; +import { ActionButton } from "../../../components//atoms/ActionButton"; +import { useEffect, useState } from "react"; +import aemServiceInstance from "../../../services/aemServiceInstance"; +import { ProjectInfo } from "../../../components/atoms/ProjectInfo"; +import Card from "../../../components/molecules/Card"; +import { createBreadcrumbs } from "../../../lib/utils/createBreadcrumbs"; +import { Heading } from "../../../components/molecules/Heading"; +import Image from "next/image"; +import stageDictionary from "../../../lib/utils/stageDictionary"; +import { sortUpdatesByDate } from "../../../lib/utils/sortUpdatesByDate"; + +export default function OasBenefitsEstimator(props) { + const [pageData] = useState(props.pageData.item); + const updatesData = sortUpdatesByDate(props.updatesData); + const [filteredDictionary] = useState( + props.dictionary.items.filter( + (item) => + item.scId === "STARTED" || + item.scId === "ENDED" || + item.scId === "PROJECT-STAGE" || + item.scId === "SUMMARY" + ) + ); + + const displayProjectUpdates = updatesData.map((update) => ( + <li key={update.scId} className="list-none ml-0 col-span-12 lg:col-span-4"> + <Card + showImage + imgSrc={ + props.locale === "en" + ? `https://www.canada.ca${update.scSocialMediaImageEn._path}` + : `https://www.canada.ca${update.scSocialMediaImageFr._path}` + } + imgAlt={ + (props.locale === "en" + ? update.scSocialMediaImageAltTextEn + : update.scSocialMediaImageAltTextFr) ?? "" + } + imgHeight={update.scSocialMediaImageEn.height} + imgWidth={update.scSocialMediaImageEn.width} + title={props.locale === "en" ? update.scTitleEn : update.scTitleFr} + href={props.locale === "en" ? update.scPageNameEn : update.scPageNameFr} + description={`${ + props.locale === "en" + ? props.dictionary.items[13].scTermEn + : props.dictionary.items[13].scTermFr + } ${update.scDateModifiedOverwrite}`} + /> + </li> + )); + + useEffect(() => { + Iif (props.adobeAnalyticsUrl) { + window.adobeDataLayer = window.adobeDataLayer || []; + window.adobeDataLayer.push({ event: "pageLoad" }); + } + }, []); + + return ( + <> + <Layout + locale={props.locale} + langUrl={ + props.locale === "en" ? pageData.scPageNameFr : pageData.scPageNameEn + } + dateModifiedOverride={pageData.scDateModifiedOverwrite} + breadcrumbItems={createBreadcrumbs( + pageData.scBreadcrumbParentPages, + props.locale + )} + > + <Head> + {/* Primary HTML Meta Tags */} + <title> + {props.locale === "en" + ? `${pageData.scTitleEn} - Service Canada Labs` + : `${pageData.scTitleFr} - Laboratoires de Service Canada`} + </title> + <meta + name="description" + content={ + props.locale === "en" + ? pageData.scDescriptionEn.json[0].content[0].value + : pageData.scDescriptionFr.json[0].content[0].value + } + /> + <meta name="author" content="Service Canada" /> + <link rel="icon" href="/favicon.ico" /> + <link + rel="canonical" + href={ + "https://alpha.service.canada.ca" + + `${ + props.locale === "en" + ? pageData.scPageNameEn + : pageData.scPageNameFr + }` + } + /> + <link rel="schema.dcterms" href="http://purl.org/dc/terms/" /> + <meta + name="keywords" + content={ + props.locale === "en" + ? pageData.scKeywordsEn + : pageData.scKeywordsFr + } + /> + + {/* DCMI Meta Tags */} + <meta + name="dcterms.title" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + <meta + name="dcterms.language" + content={props.locale === "en" ? "eng" : "fra"} + title="ISO639-2/T" + /> + <meta + name="dcterms.creator" + content={ + props.locale === "en" + ? "Employment and Social Development Canada" + : "Emploi et Développement social Canada" + } + /> + <meta name="dcterms.accessRights" content="2" /> + <meta + name="dcterms.service" + content="ESDC-EDSC_SCLabs-LaboratoireSC" + /> + <meta name="dcterms.issued" title="W3CDTF" content="2021-07-20" /> + + <meta name="dcterms.modified" title="W3CDTF" content="2021-12-16" /> + <meta + name="dcterms.description" + content={ + props.locale === "en" + ? pageData.scDescriptionEn.json[0].content[0].value + : pageData.scDescriptionFr.json[0].content[0].value + } + /> + <meta + name="dcterms.subject" + title="gccore" + content={pageData.scSubject} + /> + <meta name="dcterms.spatial" content="Canada" /> + + {/* Open Graph / Facebook */} + <meta property="og:type" content="website" /> + <meta property="og:locale" content={props.locale} /> + <meta + property="og:url" + content={ + "https://alpha.service.canada.ca" + + `${ + props.locale === "en" + ? pageData.scPageNameEn + : pageData.scPageNameFr + }` + } + /> + <meta + property="og:title" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + <meta + property="og:description" + content={ + props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[0].content[0].value + : pageData.scFragments[0].scContentFr.json[0].content[0].value + } + /> + <meta + property="og:image" + content={pageData.scSocialMediaImageEn._publishUrl} + /> + <meta + property="og:image:alt" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + + {/* Twitter */} + <meta property="twitter:card" content="summary_large_image" /> + <meta + property="twitter:url" + content={ + "https://alpha.service.canada.ca" + + `${ + props.locale === "en" + ? pageData.scPageNameEn + : pageData.scPageNameFr + }` + } + /> + <meta + property="twitter:title" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + <meta name="twitter:creator" content="Service Canada" /> + <meta + property="twitter:description" + content={ + props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[1].content[0].value + : pageData.scFragments[0].scContentFr.json[1].content[0].value + } + /> + <meta + property="twitter:image" + content={pageData.scSocialMediaImageEn._publishUrl} + /> + <meta + property="twitter:image:alt" + content={ + props.locale === "en" ? pageData.scTitleEn : pageData.scTitleFr + } + /> + </Head> + + <div className="layout-container"> + <section aria-labelledby="pageMainTitle"> + <div className="flex flex-col break-words lg:grid lg:grid-cols-2"> + <div className="col-span-2"> + <Heading + tabIndex="-1" + id="pageMainTitle" + title={ + props.locale === "en" + ? pageData.scTitleEn + : pageData.scTitleFr + } + /> + </div> + <div className="hidden lg:grid row-span-2 row-start-2 col-start-2 p-0 mx-4"> + <div className="flex justify-center"> + <div className="object-fill h-auto w-auto max-w-450px"> + <Image + src={ + props.locale === "en" + ? pageData.scFragments[1].scImageEn._publishUrl + : pageData.scFragments[1].scImageFr._publishUrl + } + alt={ + (props.locale === "en" + ? pageData.scFragments[1].scImageAltTextEn + : pageData.scFragments[1].scImageAltTextFr) ?? "" + } + height={pageData.scFragments[1].scImageEn.height} + width={pageData.scFragments[1].scImageEn.width} + priority + sizes="33vw" + quality={100} + /> + </div> + </div> + </div> + <p className="row-start-2 font-body text-lg mb-4"> + {props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[1].content[0].value + : pageData.scFragments[0].scContentFr.json[1].content[0] + .value} + </p> + <div className="row-start-3"> + <ProjectInfo + locale={props.locale} + termStarted={ + props.locale === "en" + ? filteredDictionary[2].scTermEn + : filteredDictionary[2].scTermFr + } + termStage={ + props.locale === "en" + ? filteredDictionary[1].scTermEn + : filteredDictionary[1].scTermFr + } + termSummary={ + props.locale === "en" + ? filteredDictionary[3].scTermEn + : filteredDictionary[3].scTermFr + } + dateStarted={ + pageData.scFragments[0].scContentEn.json[2].content[0].value + } + term={ + props.locale === "en" + ? pageData.scFragments[2].scContentEn.json[0].content[0] + .value + : pageData.scFragments[2].scContentFr.json[0].content[0] + .value + } + definition={ + props.locale === "en" + ? pageData.scFragments[2].scContentEn.json[0].content[1] + .value + : pageData.scFragments[2].scContentFr.json[0].content[1] + .value + } + information={ + props.locale === "en" + ? pageData.scFragments[2].scTitleEn + : pageData.scFragments[2].scTitleFr + } + stage={ + props.locale === "en" + ? stageDictionary.en[pageData.scLabProjectStage] + : stageDictionary.fr[pageData.scLabProjectStage] + } + summary={ + props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[4].content[0] + .value + : pageData.scFragments[0].scContentFr.json[4].content[0] + .value + } + /> + </div> + </div> + </section> + <div className="grid grid-cols-12"> + <h2 className="col-span-12 text-[20px]"> + {props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[5].content[0].value + : pageData.scFragments[0].scContentFr.json[5].content[0].value} + </h2> + <ActionButton + id="try-btn" + style="primary" + custom="col-span-12" + href={ + props.locale === "en" + ? pageData.scFragments[4].scDestinationURLEn + : pageData.scFragments[4].scDestinationURLFr + } + text={ + props.locale === "en" + ? pageData.scFragments[4].scTitleEn + : pageData.scFragments[4].scTitleFr + } + ariaExpanded={props.ariaExpanded} + /> + <h2 className="col-span-12"> + {props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[6].content[0].value + : pageData.scFragments[0].scContentFr.json[6].content[0].value} + </h2> + <p className="col-span-12 xl:col-span-8"> + {props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[7].content[0].value + : pageData.scFragments[0].scContentFr.json[7].content[0].value} + </p> + <p className="col-span-12 xl:col-span-8"> + {props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[8].content[0].value + : pageData.scFragments[0].scContentFr.json[8].content[0].value} + </p> + <p className="col-span-12 xl:col-span-8"> + {props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[9].content[0].value + : pageData.scFragments[0].scContentFr.json[9].content[0].value} + </p> + </div> + <h2 className="text-[20px]"> + {props.locale === "en" + ? pageData.scFragments[0].scContentEn.json[10].content[0].value + : pageData.scFragments[0].scContentFr.json[10].content[0].value} + </h2> + <div className="grid md:flex"> + <ActionButton + id="feedback-btn-2" + style="secondary" + href={ + props.locale === "en" + ? pageData.scFragments[5].scDestinationURLEn + : pageData.scFragments[5].scDestinationURLFr + } + text={ + props.locale === "en" + ? pageData.scFragments[5].scTitleEn + : pageData.scFragments[5].scTitleFr + } + ariaExpanded={props.ariaExpanded} + /> + </div> + {updatesData.length === 0 ? null : ( + <section id="projectUpdates"> + <h2> + {props.locale === "en" + ? "Project updates" + : "Mises à jour du projet"} + </h2> + <ul className="grid lg:grid-cols-12 gap-x-4 lg:gap-y-12 list-none ml-0 mb-12"> + {displayProjectUpdates} + </ul> + </section> + )} + </div> + </Layout> + </> + ); +} + +export const getStaticProps = async ({ locale }) => { + // get page data from AEM + const { data: pageData } = await aemServiceInstance.getFragment( + "oasBenefitsEstimatorQuery" + ); + // get dictionary + const { data: dictionary } = await aemServiceInstance.getFragment( + "dictionaryQuery" + ); + + return { + props: { + locale: locale, + adobeAnalyticsUrl: process.env.ADOBE_ANALYTICS_URL ?? null, + pageData: pageData.sclabsPageV1ByPath, + updatesData: pageData.sclabsPageV1ByPath.item.scLabProjectUpdates, + dictionary: dictionary.dictionaryV1List, + ...(await serverSideTranslations(locale, ["common"])), + }, + revalidate: process.env.ISR_ENABLED === "true" ? 10 : false, + }; +}; + |