Skip to content

Commit

Permalink
feat: add user prop to Layout; title to totp issuer (#64)
Browse files Browse the repository at this point in the history
  • Loading branch information
bestickley authored Mar 29, 2022
1 parent 23ff7ee commit fe28be5
Show file tree
Hide file tree
Showing 11 changed files with 95 additions and 8 deletions.
5 changes: 5 additions & 0 deletions .changeset/heavy-laws-judge.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"gboost-common": minor
---

- Add `mergeDeep` utility function
6 changes: 6 additions & 0 deletions .changeset/heavy-laws-judges.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"gboost-ui": minor
---

- Optional user prop for Layout
- Authenticator updates TOTP issuer with title by default
13 changes: 12 additions & 1 deletion docs/docs/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Instructions below allow you to edit .ts files and test out your changes without

First clone the repository and instal dependencies with `pnpm i`.

To develop `gboost-ui` or `gboost-infra` or `gboost-common`, in your Green Boost application repository (created with `gboost create`), run `pnpm add ../path/to/gboost/packages/gboost-*` replacing the path with the path to wherever the package is locally.
To develop `gboost-ui` or `gboost-infra` or `gboost-common`, in your Green Boost application repository (created with `gboost create`), run `pnpm add ../path/to/gboost/packages/gboost-*` replacing the path with the path to wherever the package is locally. This will change your package.json.

For `gboost-ui`, you'll need to add this plugin in your vite.config.ts
```ts
Expand Down Expand Up @@ -32,6 +32,17 @@ function reactJsOrJsx({
},
};
}

export default defineConfig(({ mode }) => {
// ...
return {
plugins: [
// ...
reactJsOrJsx({ importerRegExpTest: /green-boost/ }),
],
//...
};
});
```

If you run into issues with duplicate node_modules being resolved, check out [this](https://blog.maximeheckel.com/posts/duplicate-dependencies-npm-link/) article and look at Vite's `dedupe` config but you shouldn't need to.
Expand Down
1 change: 1 addition & 0 deletions packages/gboost-common/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./convertCase.js";
export * from "./user-management.js";
export * from "./mergeDeep.js";
33 changes: 33 additions & 0 deletions packages/gboost-common/src/mergeDeep.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* Simple object check.
* @param item
* @returns {boolean}
*/
export function isObject(item: object | undefined): boolean | undefined {
return item && typeof item === "object" && !Array.isArray(item);
}

/**
* Deep merge two objects.
* @param target
* @param ...sources
* @link https://stackoverflow.com/a/34749873/9658768
*/
export function mergeDeep(target: object, ...sources: object[]): object {
if (!sources.length) return target;
const source = sources.shift();

if (isObject(target) && isObject(source)) {
for (const key in source) {
const typedKey = key as keyof typeof source;
if (isObject(source[typedKey])) {
if (!target[typedKey]) Object.assign(target, { [typedKey]: {} });
mergeDeep(target[typedKey], source[typedKey]);
} else {
Object.assign(target, { [key]: source[typedKey] });
}
}
}

return mergeDeep(target, ...sources);
}
15 changes: 14 additions & 1 deletion packages/gboost-ui/src/Authenticator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
Image,
View,
} from "@aws-amplify/ui-react";
import { mergeDeep } from "gboost-common";
import { Box } from "./Box.js";
import { styled } from "./stitches.config.js";
import { ArgumentTypes } from "./utils/ArgumentTypes.js";
Expand All @@ -24,7 +25,18 @@ const StyledHeading = styled(Heading, { fontSize: "$8 !important" });
* @link https://ui.docs.amplify.aws/components/authenticator?platform=react
*/
export function Authenticator(props: AuthenticatorProps): ReactElement {
const { children, signUpAttributes, components = {}, title, ...rest } = props;
const {
children,
formFields: passedFormFields,
signUpAttributes,
components = {},
title,
...rest
} = props;
const initFormFields = { setupTOTP: { QR: { totpIssuer: title } } };
const formFields = passedFormFields
? mergeDeep(passedFormFields, initFormFields)
: initFormFields;
const newComponents = {
Header() {
return (
Expand All @@ -42,6 +54,7 @@ export function Authenticator(props: AuthenticatorProps): ReactElement {
<StyledAuthenticator
components={newComponents}
signUpAttributes={signUpAttributes}
formFields={formFields}
{...rest}
>
{children}
Expand Down
11 changes: 7 additions & 4 deletions packages/gboost-ui/src/Layout/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ import {
} from "@aws-amplify/ui-react";
import { Dispatch, ReactElement, SetStateAction, useState } from "react";
import { MdAccountCircle, MdLogout, MdMenu, MdMenuOpen } from "react-icons/md";
import { useNavigate } from "react-router-dom";
import { useAuthenticator } from "@aws-amplify/ui-react";
import { useBps } from "../context/BreakpointsContext";
import { styled } from "../stitches.config.js";
import { Box } from "../Box.js";
import { Drawer } from "./Drawer.js";
import { List, ListItem } from "../List.js";
import { useNavigate } from "react-router-dom";
import { useAuthenticator } from "@aws-amplify/ui-react";
import type { CognitoUser } from "./Layout.js";

const headerHeight = "$8";

Expand Down Expand Up @@ -47,12 +48,14 @@ interface HeaderProps {
open: boolean;
setOpen: Dispatch<SetStateAction<boolean>>;
title: string;
user?: CognitoUser;
HeaderTitle?: ReactElement;
}

export function Header(props: HeaderProps): ReactElement {
const { logoSrc, setOpen, open, title, HeaderTitle } = props;
const { user, signOut } = useAuthenticator();
const { logoSrc, setOpen, open, title, user: propUser, HeaderTitle } = props;
const { user: hookUser, signOut } = useAuthenticator();
const user = propUser || hookUser;
const [leftOpen, setLeftOpen] = useState(false);
const bps = useBps();
const navigate = useNavigate();
Expand Down
10 changes: 10 additions & 0 deletions packages/gboost-ui/src/Layout/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import { Footer } from "./Footer.js";
import { Box } from "../Box.js";
import { Drawer } from "./Drawer.js";
import { NavList } from "./NavList.js";
import { useAuthenticator } from "@aws-amplify/ui-react";

export type CognitoUser = ReturnType<typeof useAuthenticator>["user"];

export interface LayoutProps {
className?: string;
Expand All @@ -32,6 +35,11 @@ export interface LayoutProps {
* string for header title
*/
title: string;
/**
* Explicitly defined user for Account Menu instead of using `user` returned
* from `useAuthenticator`
*/
user?: CognitoUser;
/**
* React component for Footer. When used, `footer` prop is ignored
*/
Expand All @@ -53,6 +61,7 @@ export function Layout(props: LayoutProps): ReactElement {
logoSrc,
pages,
title,
user,
Footer: UserFooter,
HeaderTitle,
} = props;
Expand Down Expand Up @@ -97,6 +106,7 @@ export function Layout(props: LayoutProps): ReactElement {
open={open}
setOpen={setOpen}
title={title}
user={user}
HeaderTitle={HeaderTitle}
/>
{nav}
Expand Down
1 change: 1 addition & 0 deletions packages/gboost-ui/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ export * from "./Dialog.js";
export type { TransferListProps } from "./TransferList.js";
export { RefTransferList as TransferList } from "./TransferList.js";
export * from "./SmartInputs/SmartInputs.js";
export * from "./Loading.js";
1 change: 1 addition & 0 deletions packages/gboost/_templates/repo/create/ui/.eslintrc.cjs.t
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module.exports = defineConfig({
extends: [
"react-app", // use CRA linting rules
"react-app/jest",
"plugin:prettier/recommended",
],
rules: {
// Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs
Expand Down
7 changes: 5 additions & 2 deletions packages/gboost/_templates/repo/create/ui/src/App.tsx.t
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,18 @@ import { theme } from "./theme.js";
const signUpAttributes = Object.keys(userAttributes).map(
camelToSnake
) as "email"[]; // amplify doesn't export SignUpAttribute type
const title = import.meta.env.VITE_APP_TITLE as string;

export function App() {
globalStyles();
const title = import.meta.env.VITE_APP_TITLE as string;
return (
<AmplifyProvider theme={getAmplifyTheme(theme)}>
<BreakpointsProvider media={config.media}>
<NotificationsProvider>
<Authenticator signUpAttributes={signUpAttributes} title={title}>
<Authenticator
signUpAttributes={signUpAttributes}
title={title}
>
{() => (
<Layout
className={theme}
Expand Down

0 comments on commit fe28be5

Please sign in to comment.