diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 1b2570d74..3c7876300 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -10,13 +10,14 @@ "hasInstallScript": true, "dependencies": { "@next/third-parties": "^14.0.4", - "@trussworks/react-uswds": "^5.0.0", + "@trussworks/react-uswds": "^7.0.0", "@uswds/uswds": "^3.6.0", "i18next": "^23.0.0", "js-cookie": "^3.0.5", "lodash": "^4.17.21", - "next": "^13.5.2", + "next": "^14.0.3", "next-i18next": "^15.0.0", + "next-intl": "^3.2.1", "react": "^18.2.0", "react-dom": "^18.2.0", "react-i18next": "^14.0.0", @@ -3486,6 +3487,92 @@ "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==", "dev": true }, + "node_modules/@formatjs/ecma402-abstract": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.18.2.tgz", + "integrity": "sha512-+QoPW4csYALsQIl8GbN14igZzDbuwzcpWrku9nyMXlaqAlwRBgl5V+p0vWMGFqHOw37czNXaP/lEk4wbLgcmtA==", + "dependencies": { + "@formatjs/intl-localematcher": "0.5.4", + "tslib": "^2.4.0" + } + }, + "node_modules/@formatjs/ecma402-abstract/node_modules/@formatjs/intl-localematcher": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.4.tgz", + "integrity": "sha512-zTwEpWOzZ2CiKcB93BLngUX59hQkuZjT2+SAQEscSm52peDW/getsawMcWF1rGRpMCX6D7nSJA3CzJ8gn13N/g==", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@formatjs/fast-memoize": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-1.2.1.tgz", + "integrity": "sha512-Rg0e76nomkz3vF9IPlKeV+Qynok0r7YZjL6syLz4/urSg0IbjPZCB/iYUMNsYA643gh4mgrX3T7KEIFIxJBQeg==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@formatjs/icu-messageformat-parser": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.1.0.tgz", + "integrity": "sha512-Qxv/lmCN6hKpBSss2uQ8IROVnta2r9jd3ymUEIjm2UyIkUCHVcbUVRGL/KS/wv7876edvsPe+hjHVJ4z8YuVaw==", + "dependencies": { + "@formatjs/ecma402-abstract": "1.11.4", + "@formatjs/icu-skeleton-parser": "1.3.6", + "tslib": "^2.1.0" + } + }, + "node_modules/@formatjs/icu-messageformat-parser/node_modules/@formatjs/ecma402-abstract": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.4.tgz", + "integrity": "sha512-EBikYFp2JCdIfGEb5G9dyCkTGDmC57KSHhRQOC3aYxoPWVZvfWCDjZwkGYHN7Lis/fmuWl906bnNTJifDQ3sXw==", + "dependencies": { + "@formatjs/intl-localematcher": "0.2.25", + "tslib": "^2.1.0" + } + }, + "node_modules/@formatjs/icu-messageformat-parser/node_modules/@formatjs/intl-localematcher": { + "version": "0.2.25", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.25.tgz", + "integrity": "sha512-YmLcX70BxoSopLFdLr1Ds99NdlTI2oWoLbaUW2M406lxOIPzE1KQhRz2fPUkq34xVZQaihCoU29h0KK7An3bhA==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@formatjs/icu-skeleton-parser": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.6.tgz", + "integrity": "sha512-I96mOxvml/YLrwU2Txnd4klA7V8fRhb6JG/4hm3VMNmeJo1F03IpV2L3wWt7EweqNLES59SZ4d6hVOPCSf80Bg==", + "dependencies": { + "@formatjs/ecma402-abstract": "1.11.4", + "tslib": "^2.1.0" + } + }, + "node_modules/@formatjs/icu-skeleton-parser/node_modules/@formatjs/ecma402-abstract": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.4.tgz", + "integrity": "sha512-EBikYFp2JCdIfGEb5G9dyCkTGDmC57KSHhRQOC3aYxoPWVZvfWCDjZwkGYHN7Lis/fmuWl906bnNTJifDQ3sXw==", + "dependencies": { + "@formatjs/intl-localematcher": "0.2.25", + "tslib": "^2.1.0" + } + }, + "node_modules/@formatjs/icu-skeleton-parser/node_modules/@formatjs/intl-localematcher": { + "version": "0.2.25", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.25.tgz", + "integrity": "sha512-YmLcX70BxoSopLFdLr1Ds99NdlTI2oWoLbaUW2M406lxOIPzE1KQhRz2fPUkq34xVZQaihCoU29h0KK7An3bhA==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@formatjs/intl-localematcher": { + "version": "0.2.32", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.32.tgz", + "integrity": "sha512-k/MEBstff4sttohyEpXxCmC3MqbUn9VvHGlZ8fauLzkbwXmVrEeyzS+4uhrvAk9DWU9/7otYWxyDox4nT/KVLQ==", + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -4814,9 +4901,9 @@ } }, "node_modules/@next/env": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.5.6.tgz", - "integrity": "sha512-Yac/bV5sBGkkEXmAX5FWPS9Mmo2rthrOPRQQNfycJPkjUAUclomCPH7QFVCDQ4Mp2k2K1SSM6m0zrxYrOwtFQw==" + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.1.0.tgz", + "integrity": "sha512-Py8zIo+02ht82brwwhTg36iogzFqGLPXlRGKQw5s+qP/kMNc4MAyDeEwBKDijk6zTIbegEgu8Qy7C1LboslQAw==" }, "node_modules/@next/eslint-plugin-next": { "version": "13.5.6", @@ -4848,9 +4935,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.5.6.tgz", - "integrity": "sha512-5nvXMzKtZfvcu4BhtV0KH1oGv4XEW+B+jOfmBdpFI3C7FrB/MfujRpWYSBBO64+qbW8pkZiSyQv9eiwnn5VIQA==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.1.0.tgz", + "integrity": "sha512-nUDn7TOGcIeyQni6lZHfzNoo9S0euXnu0jhsbMOmMJUBfgsnESdjN97kM7cBqQxZa8L/bM9om/S5/1dzCrW6wQ==", "cpu": [ "arm64" ], @@ -4863,9 +4950,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.5.6.tgz", - "integrity": "sha512-6cgBfxg98oOCSr4BckWjLLgiVwlL3vlLj8hXg2b+nDgm4bC/qVXXLfpLB9FHdoDu4057hzywbxKvmYGmi7yUzA==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.1.0.tgz", + "integrity": "sha512-1jgudN5haWxiAl3O1ljUS2GfupPmcftu2RYJqZiMJmmbBT5M1XDffjUtRUzP4W3cBHsrvkfOFdQ71hAreNQP6g==", "cpu": [ "x64" ], @@ -4878,9 +4965,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.5.6.tgz", - "integrity": "sha512-txagBbj1e1w47YQjcKgSU4rRVQ7uF29YpnlHV5xuVUsgCUf2FmyfJ3CPjZUvpIeXCJAoMCFAoGnbtX86BK7+sg==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.1.0.tgz", + "integrity": "sha512-RHo7Tcj+jllXUbK7xk2NyIDod3YcCPDZxj1WLIYxd709BQ7WuRYl3OWUNG+WUfqeQBds6kvZYlc42NJJTNi4tQ==", "cpu": [ "arm64" ], @@ -4893,9 +4980,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.5.6.tgz", - "integrity": "sha512-cGd+H8amifT86ZldVJtAKDxUqeFyLWW+v2NlBULnLAdWsiuuN8TuhVBt8ZNpCqcAuoruoSWynvMWixTFcroq+Q==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.1.0.tgz", + "integrity": "sha512-v6kP8sHYxjO8RwHmWMJSq7VZP2nYCkRVQ0qolh2l6xroe9QjbgV8siTbduED4u0hlk0+tjS6/Tuy4n5XCp+l6g==", "cpu": [ "arm64" ], @@ -4908,9 +4995,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.5.6.tgz", - "integrity": "sha512-Mc2b4xiIWKXIhBy2NBTwOxGD3nHLmq4keFk+d4/WL5fMsB8XdJRdtUlL87SqVCTSaf1BRuQQf1HvXZcy+rq3Nw==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.1.0.tgz", + "integrity": "sha512-zJ2pnoFYB1F4vmEVlb/eSe+VH679zT1VdXlZKX+pE66grOgjmKJHKacf82g/sWE4MQ4Rk2FMBCRnX+l6/TVYzQ==", "cpu": [ "x64" ], @@ -4923,9 +5010,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.5.6.tgz", - "integrity": "sha512-CFHvP9Qz98NruJiUnCe61O6GveKKHpJLloXbDSWRhqhkJdZD2zU5hG+gtVJR//tyW897izuHpM6Gtf6+sNgJPQ==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.1.0.tgz", + "integrity": "sha512-rbaIYFt2X9YZBSbH/CwGAjbBG2/MrACCVu2X0+kSykHzHnYH5FjHxwXLkcoJ10cX0aWCEynpu+rP76x0914atg==", "cpu": [ "x64" ], @@ -4938,9 +5025,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.5.6.tgz", - "integrity": "sha512-aFv1ejfkbS7PUa1qVPwzDHjQWQtknzAZWGTKYIAaS4NMtBlk3VyA6AYn593pqNanlicewqyl2jUhQAaFV/qXsg==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.1.0.tgz", + "integrity": "sha512-o1N5TsYc8f/HpGt39OUQpQ9AKIGApd3QLueu7hXk//2xq5Z9OxmV6sQfNp8C7qYmiOlHYODOGqNNa0e9jvchGQ==", "cpu": [ "arm64" ], @@ -4953,9 +5040,9 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.5.6.tgz", - "integrity": "sha512-XqqpHgEIlBHvzwG8sp/JXMFkLAfGLqkbVsyN+/Ih1mR8INb6YCc2x/Mbwi6hsAgUnqQztz8cvEbHJUbSl7RHDg==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.1.0.tgz", + "integrity": "sha512-XXIuB1DBRCFwNO6EEzCTMHT5pauwaSj4SWs7CYnME57eaReAKBXCnkUE80p/pAZcewm7hs+vGvNqDPacEXHVkw==", "cpu": [ "ia32" ], @@ -4968,9 +5055,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.5.6.tgz", - "integrity": "sha512-Cqfe1YmOS7k+5mGu92nl5ULkzpKuxJrP3+4AEuPmrpFZ3BHxTY3TnHmU1On3bFmFFs6FbTcdF58CCUProGpIGQ==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.1.0.tgz", + "integrity": "sha512-9WEbVRRAqJ3YFVqEZIxUqkiO8l1nool1LmNxygr5HWF8AcSYsEpneUDhmjUVJEzO2A04+oPtZdombzzPPkTtgg==", "cpu": [ "x64" ], @@ -7615,14 +7702,14 @@ } }, "node_modules/@trussworks/react-uswds": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@trussworks/react-uswds/-/react-uswds-5.5.0.tgz", - "integrity": "sha512-PZRklIYWIIXI+hTw2XILPHKictZXwnPaSZf9L1mRTmfj1IncktPPpCCigwfIxIG6MSMzZYXx/TOAwjb8n4sjhw==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@trussworks/react-uswds/-/react-uswds-7.0.0.tgz", + "integrity": "sha512-N3O0BRuhyLoZKjYM0Mq+XIXJ3ShvCEh6uhqwRstIde6E9m0Au6JLy1YEv9A8eapBxDvyqZW3jiVTGzW/JqS+eA==", "engines": { "node": ">= 16.20.0" }, "peerDependencies": { - "@uswds/uswds": "^3.6.0", + "@uswds/uswds": "^3.7.1", "react": "^16.x || ^17.x || ^18.x", "react-dom": "^16.x || ^17.x || ^18.x" } @@ -13936,7 +14023,8 @@ "node_modules/glob-to-regexp": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true }, "node_modules/glob/node_modules/brace-expansion": { "version": "2.0.1", @@ -14718,6 +14806,34 @@ "node": ">= 0.4" } }, + "node_modules/intl-messageformat": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-9.13.0.tgz", + "integrity": "sha512-7sGC7QnSQGa5LZP7bXLDhVDtQOeKGeBFGHF2Y8LVBwYZoQZCgWeKoPGTa5GMG8g/TzDgeXuYJQis7Ggiw2xTOw==", + "dependencies": { + "@formatjs/ecma402-abstract": "1.11.4", + "@formatjs/fast-memoize": "1.2.1", + "@formatjs/icu-messageformat-parser": "2.1.0", + "tslib": "^2.1.0" + } + }, + "node_modules/intl-messageformat/node_modules/@formatjs/ecma402-abstract": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.4.tgz", + "integrity": "sha512-EBikYFp2JCdIfGEb5G9dyCkTGDmC57KSHhRQOC3aYxoPWVZvfWCDjZwkGYHN7Lis/fmuWl906bnNTJifDQ3sXw==", + "dependencies": { + "@formatjs/intl-localematcher": "0.2.25", + "tslib": "^2.1.0" + } + }, + "node_modules/intl-messageformat/node_modules/@formatjs/intl-localematcher": { + "version": "0.2.25", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.25.tgz", + "integrity": "sha512-YmLcX70BxoSopLFdLr1Ds99NdlTI2oWoLbaUW2M406lxOIPzE1KQhRz2fPUkq34xVZQaihCoU29h0KK7An3bhA==", + "dependencies": { + "tslib": "^2.1.0" + } + }, "node_modules/invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", @@ -18214,7 +18330,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -18226,34 +18341,34 @@ "dev": true }, "node_modules/next": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/next/-/next-13.5.6.tgz", - "integrity": "sha512-Y2wTcTbO4WwEsVb4A8VSnOsG1I9ok+h74q0ZdxkwM3EODqrs4pasq7O0iUxbcS9VtWMicG7f3+HAj0r1+NtKSw==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/next/-/next-14.1.0.tgz", + "integrity": "sha512-wlzrsbfeSU48YQBjZhDzOwhWhGsy+uQycR8bHAOt1LY1bn3zZEcDyHQOEoN3aWzQ8LHCAJ1nqrWCc9XF2+O45Q==", "dependencies": { - "@next/env": "13.5.6", + "@next/env": "14.1.0", "@swc/helpers": "0.5.2", "busboy": "1.6.0", - "caniuse-lite": "^1.0.30001406", + "caniuse-lite": "^1.0.30001579", + "graceful-fs": "^4.2.11", "postcss": "8.4.31", - "styled-jsx": "5.1.1", - "watchpack": "2.4.0" + "styled-jsx": "5.1.1" }, "bin": { "next": "dist/bin/next" }, "engines": { - "node": ">=16.14.0" + "node": ">=18.17.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "13.5.6", - "@next/swc-darwin-x64": "13.5.6", - "@next/swc-linux-arm64-gnu": "13.5.6", - "@next/swc-linux-arm64-musl": "13.5.6", - "@next/swc-linux-x64-gnu": "13.5.6", - "@next/swc-linux-x64-musl": "13.5.6", - "@next/swc-win32-arm64-msvc": "13.5.6", - "@next/swc-win32-ia32-msvc": "13.5.6", - "@next/swc-win32-x64-msvc": "13.5.6" + "@next/swc-darwin-arm64": "14.1.0", + "@next/swc-darwin-x64": "14.1.0", + "@next/swc-linux-arm64-gnu": "14.1.0", + "@next/swc-linux-arm64-musl": "14.1.0", + "@next/swc-linux-x64-gnu": "14.1.0", + "@next/swc-linux-x64-musl": "14.1.0", + "@next/swc-win32-arm64-msvc": "14.1.0", + "@next/swc-win32-ia32-msvc": "14.1.0", + "@next/swc-win32-x64-msvc": "14.1.0" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", @@ -18305,6 +18420,26 @@ "react-i18next": ">= 13.5.0" } }, + "node_modules/next-intl": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/next-intl/-/next-intl-3.9.1.tgz", + "integrity": "sha512-1j+5lLTY5kHshqnVoeAep+gQO1xX1KlJU3irZkdCOhr0woo562qLKOsGGVh+7bB5luBMu9qQBQy7ZwNK81Z2Ig==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/amannn" + } + ], + "dependencies": { + "@formatjs/intl-localematcher": "^0.2.32", + "negotiator": "^0.6.3", + "use-intl": "^3.9.1" + }, + "peerDependencies": { + "next": "^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/next/node_modules/postcss": { "version": "8.4.31", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", @@ -23510,6 +23645,18 @@ } } }, + "node_modules/use-intl": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/use-intl/-/use-intl-3.9.1.tgz", + "integrity": "sha512-tWcT636/jYC0hILyFTLmiuE+ovbvPPBXwN/OOQxxE+4bssHXeeksdWXzpDsKqE37aV62DFrQ2jhumV8udecjNA==", + "dependencies": { + "@formatjs/ecma402-abstract": "^1.11.4", + "intl-messageformat": "^9.3.18" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/use-resize-observer": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/use-resize-observer/-/use-resize-observer-9.1.0.tgz", @@ -23664,6 +23811,7 @@ "version": "2.4.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" diff --git a/frontend/package.json b/frontend/package.json index 17da166cd..db5761a65 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -23,13 +23,14 @@ }, "dependencies": { "@next/third-parties": "^14.0.4", - "@trussworks/react-uswds": "^5.0.0", + "@trussworks/react-uswds": "^7.0.0", "@uswds/uswds": "^3.6.0", "i18next": "^23.0.0", "js-cookie": "^3.0.5", "lodash": "^4.17.21", - "next": "^13.5.2", + "next": "^14.0.3", "next-i18next": "^15.0.0", + "next-intl": "^3.2.1", "react": "^18.2.0", "react-dom": "^18.2.0", "react-i18next": "^14.0.0", diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx new file mode 100644 index 000000000..8ca2d93e1 --- /dev/null +++ b/frontend/src/app/layout.tsx @@ -0,0 +1,32 @@ +/** + * Root layout component, wraps all pages. + * @see https://nextjs.org/docs/app/api-reference/file-conventions/layout + */ +import { Metadata } from "next"; + +import Layout from "src/components/AppLayout"; + +import "src/styles/styles.scss"; + +export const metadata: Metadata = { + icons: [`${process.env.NEXT_PUBLIC_BASE_PATH ?? ""}/img/logo.svg`], +}; + +interface LayoutProps { + children: React.ReactNode; + params: { + locale: string; + }; +} + +export default function RootLayout({ children, params }: LayoutProps) { + return ( + + + {/* Separate layout component for the inner-body UI elements since Storybook + and tests trip over the fact that this file renders an tag */} + {children} + + + ); +} \ No newline at end of file diff --git a/frontend/src/app/search2/page.tsx b/frontend/src/app/search2/page.tsx new file mode 100644 index 000000000..f2be9f7dc --- /dev/null +++ b/frontend/src/app/search2/page.tsx @@ -0,0 +1,60 @@ +"use client"; +import type { GetStaticProps, NextPage } from "next"; +import { useFeatureFlags } from "src/hooks/useFeatureFlags"; + +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; +import React, { useState } from "react"; + +import { APISearchFetcher } from "../../services/searchfetcher/APISearchFetcher"; +import { MockSearchFetcher } from "../../services/searchfetcher/MockSearchFetcher"; +import { + fetchSearchOpportunities, + SearchFetcher, +} from "../../services/searchfetcher/SearchFetcher"; +import { Opportunity } from "../../types/searchTypes"; +import PageNotFound from "../../pages/404"; + +const useMockData = true; +const searchFetcher: SearchFetcher = useMockData + ? new MockSearchFetcher() + : new APISearchFetcher(); + +interface SearchProps { + initialOpportunities: Opportunity[]; +} + +const Search: NextPage = ({ initialOpportunities = [] }) => { + const { featureFlagsManager, mounted } = useFeatureFlags(); + const [searchResults, setSearchResults] = + useState(initialOpportunities); + + const handleButtonClick = (event: React.MouseEvent) => { + event.preventDefault(); + performSearch().catch((e) => console.log(e)); + }; + + const performSearch = async () => { + const opportunities = await fetchSearchOpportunities(searchFetcher); + setSearchResults(opportunities); + }; + + if (!mounted) return null; + if (!featureFlagsManager.isFeatureEnabled("showSearchV0")) { + return ; + } + + return ( + <> + +
    + {searchResults.map((opportunity) => ( +
  • + {opportunity.id}, {opportunity.title} +
  • + ))} +
+ + ); +}; + +export default Search; diff --git a/frontend/src/components/AppFooter.tsx b/frontend/src/components/AppFooter.tsx new file mode 100644 index 000000000..7cfab8be7 --- /dev/null +++ b/frontend/src/components/AppFooter.tsx @@ -0,0 +1,119 @@ +'use client'; + +import { ExternalRoutes } from "src/constants/routes"; +import { assetPath } from "src/utils/assetPath"; + +import { ComponentType } from "react"; +import { + Address, + Grid, + GridContainer, + Icon, + SocialLinks, + Footer as USWDSFooter, +} from "@trussworks/react-uswds"; +import { IconProps } from "@trussworks/react-uswds/lib/components/Icon/Icon"; + +// Recreate @trussworks/react-uswds SocialLink component to accept any Icon +// https://github.com/trussworks/react-uswds/blob/cf5b4555e25f0e52fc8af66afe29253922bed2a5/src/components/Footer/SocialLinks/SocialLinks.tsx#L33 +type SocialLinkProps = { + href: string; + name: string; + Tag: ComponentType; +}; + +const SocialLink = ({ href, name, Tag }: SocialLinkProps) => ( + + + +); + +const Footer = () => { + + const links = [ + { + href: ExternalRoutes.GRANTS_TWITTER, + name: "link_twitter", + Tag: Icon.Twitter, + }, + { + href: ExternalRoutes.GRANTS_YOUTUBE, + name: "link_youtube", + Tag: Icon.Youtube, + }, + { + href: ExternalRoutes.GRANTS_BLOG, + name: "link_blog", + Tag: Icon.LocalLibrary, + }, + { + href: ExternalRoutes.GRANTS_NEWSLETTER, + name: "link_newsletter", + Tag: Icon.Mail, + }, + { + href: ExternalRoutes.GRANTS_RSS, + name: "link_rss", + Tag: Icon.RssFeed, + }, + { + href: ExternalRoutes.GITHUB_REPO, + name: "link_github", + Tag: Icon.Github, + }, + ].map(({ href, name, Tag }) => ( + + )); + + return ( + + {"return_to_top"} + + } + primary={null} + secondary={ + + + {"logo_alt"} + + + +

+ {"agency_contact_center"} +

+
+ {"telephone"} + , + + {ExternalRoutes.EMAIL_SUPPORT} + , + ]} + /> + + + } + /> + ); +}; + +export default Footer; diff --git a/frontend/src/components/AppGrantsIdentifier.tsx b/frontend/src/components/AppGrantsIdentifier.tsx new file mode 100644 index 000000000..52e7e4097 --- /dev/null +++ b/frontend/src/components/AppGrantsIdentifier.tsx @@ -0,0 +1,83 @@ +import { ExternalRoutes } from "src/constants/routes"; + +import Image from "next/image"; +import { + Identifier, + IdentifierGov, + IdentifierIdentity, + IdentifierLink, + IdentifierLinkItem, + IdentifierLinks, + IdentifierLogo, + IdentifierLogos, + IdentifierMasthead, +} from "@trussworks/react-uswds"; + +import logo from "../../public/img/logo-white-lg.webp"; + +const GrantsIdentifier = () => { + + const logoImage = ( + {"logo_alt"} + ); + + const IdentifierLinkList = [ + { + href: ExternalRoutes.ABOUT_HHS, + text: "link_about", + }, + { + href: ExternalRoutes.ACCESSIBILITY_COMPLIANCE, + text: "link_accessibility", + }, + { + href: ExternalRoutes.FOIA, + text: "link_foia", + }, + { + href: ExternalRoutes.NO_FEAR, + text: "link_fear", + }, + { + href: ExternalRoutes.INSPECTOR_GENERAL, + text: "link_ig", + }, + { + href: ExternalRoutes.PERFORMANCE_REPORTS, + text: "link_performance", + }, + { + href: ExternalRoutes.PRIVACY_POLICY, + text: "link_privacy", + }, + ].map(({ text, href }) => ( + + + {text} + + + )); + + return ( + + + + {logoImage} + + + + + + {IdentifierLinkList} + + + + + ); +}; + +export default GrantsIdentifier; diff --git a/frontend/src/components/AppHeader.tsx b/frontend/src/components/AppHeader.tsx new file mode 100644 index 000000000..262128299 --- /dev/null +++ b/frontend/src/components/AppHeader.tsx @@ -0,0 +1,84 @@ +'use client'; + +import { assetPath } from "src/utils/assetPath"; + +import { useState } from "react"; +import { + GovBanner, + NavMenuButton, + PrimaryNav, + Title, + Header as USWDSHeader, +} from "@trussworks/react-uswds"; + +type PrimaryLinks = { + i18nKey: string; + href: string; +}[]; + +const primaryLinks: PrimaryLinks = [ + { i18nKey: "Home", href: "/" }, + { i18nKey: "Process", href: "/process" }, + { i18nKey: "Reseach", href: "/research" }, + { i18nKey: "Newsletter", href: "/newsletter" }, +]; + +type Props = { + logoPath?: string; +}; + +const Header = ({ logoPath }: Props) => { + + const [isMobileNavExpanded, setIsMobileNavExpanded] = useState(false); + const handleMobileNavToggle = () => { + setIsMobileNavExpanded(!isMobileNavExpanded); + }; + + const navItems = primaryLinks.map((link) => ( + + {link.i18nKey} + + )); + + return ( + <> +
+ + +
+
+ + <div className="display-flex flex-align-center"> + {logoPath && ( + <span className="margin-right-1"> + <img + className="width-3 desktop:width-5 text-bottom margin-right-05" + src={assetPath(logoPath)} + alt="Site logo" + /> + </span> + )} + <span className="font-sans-lg flex-fill">{"title"}</span> + </div> + + +
+ +
+
+ + ); +}; + +export default Header; diff --git a/frontend/src/components/AppLayout.tsx b/frontend/src/components/AppLayout.tsx new file mode 100644 index 000000000..cdc713b7a --- /dev/null +++ b/frontend/src/components/AppLayout.tsx @@ -0,0 +1,29 @@ + +import { GovBanner, Grid, GridContainer } from "@trussworks/react-uswds"; + +import AppFooter from "./AppFooter"; +import GrantsIdentifier from "./AppGrantsIdentifier"; +import Header from "./AppHeader"; + +type Props = { + children: React.ReactNode; + locale?: string; +}; + +const Layout = ({ children, locale }: Props) => { + + return ( + // Stick the footer to the bottom of the page +
+ + {"skip_to_main"} + +
+
{children}
+ + +
+ ); +}; + +export default Layout; \ No newline at end of file