Skip to content

Commit

Permalink
chore: Update portal-administration package and add router components
Browse files Browse the repository at this point in the history
- Modify portal-administration/package.json
- Add new files: portal-administration/src/components/Router/RouteMenu.tsx, portal-administration/src/components/Router/RouteTreeItem.tsx, portal-administration/src/components/Router/RouterEdit.tsx, portal-administration/src/components/Router/RouterTree.tsx, portal-administration/src/context/RouterContext.tsx, portal-administration/src/context/actions/add-route-router-actions.test.ts, portal-administration/src/context/actions/router-actions.ts, portal-administration/src/context/reducers/router-reducer.ts, portal-administration/src/schema/route.ts, portal-administration/src/types/router-config.ts
- Modify portal-administration/src/components/Tree.tsx
- Modify portal-administration/src/pages/RouterConfig.tsx
- Modify portal-administration/yarn.lock
  • Loading branch information
Noggling committed Aug 28, 2024
1 parent c53453c commit 36aa2ca
Show file tree
Hide file tree
Showing 21 changed files with 1,409 additions and 371 deletions.
3 changes: 2 additions & 1 deletion portal-administration/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.26.0",
"typescript": "^5.1.3"
"typescript": "^5.1.3",
"vitest": "^2.0.5"
},
"dependencies": {
"@ag-grid-community/core": "^32.1.0",
Expand Down
87 changes: 87 additions & 0 deletions portal-administration/src/components/Router/RouteMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { Button, Icon, Menu, Typography } from "@equinor/eds-core-react";

import styled from "styled-components";
import { useState } from "react";

import { add, edit, more_vertical, remove_outlined } from "@equinor/eds-icons";
import { tokens } from "@equinor/eds-tokens";
import { Route } from "../../types/router-config";
import { useRouterConfigContext } from "../../context/RouterContext";

export const RouteMenu = ({ route }: { route: Route }) => {
const [isOpen, setIsOpen] = useState<boolean>(false);
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
const { createNewRoute, removeRoute, setActiveRoute } =
useRouterConfigContext();

const openMenu = () => {
setIsOpen(true);
};

const closeMenu = () => {
setIsOpen(false);
};

return (
<div>
<Button
ref={setAnchorEl}
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
openMenu();
}}
variant="ghost_icon"
>
<Icon data={more_vertical} />
</Button>

<Menu open={isOpen} onClose={closeMenu} anchorEl={anchorEl}>
<Menu.Item
onClick={() => {
console.log(route);
setActiveRoute(route.id);
}}
>
<Icon
data={edit}
size={16}
color={tokens.colors.text.static_icons__tertiary.hex}
/>
<Typography group="navigation" variant="menu_title" as="span">
Edit
</Typography>
</Menu.Item>
<Menu.Item
onClick={() => {
console.log(route);
createNewRoute(route.id);
}}
>
<Icon
data={add}
size={16}
color={tokens.colors.text.static_icons__tertiary.hex}
/>
<Typography group="navigation" variant="menu_title" as="span">
Add
</Typography>
</Menu.Item>
<Menu.Item
onClick={() => {
removeRoute(route.id);
}}
>
<Icon
data={remove_outlined}
size={16}
color={tokens.colors.text.static_icons__tertiary.hex}
/>
<Typography group="navigation" variant="menu_title" as="span">
Remove
</Typography>
</Menu.Item>
</Menu>
</div>
);
};
43 changes: 43 additions & 0 deletions portal-administration/src/components/Router/RouteTreeItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { tokens } from "@equinor/eds-tokens";
import { TreeItem } from "../Tree";
import { Route } from "../../types/router-config";
import { RouteMenu } from "./RouteMenu";
import { useRouterConfigContext } from "../../context/RouterContext";
import { Typography } from "@equinor/eds-core-react";
import styled from "styled-components";

const Style = {
Wrapper: styled.div`
display: flex;
flex-direction: row;
align-items: center;
`,
};

export const RouteTreeItem = ({ route }: { route: Route }) => {
const { activeRoute, setActiveRoute } = useRouterConfigContext();
return (
<TreeItem
onClick={() => setActiveRoute(route.id)}
selected={
activeRoute?.id === route.id
? tokens.colors.interactive.primary__selected_highlight.hex
: undefined
}
title={route.path}
key={route.path}
Render={() => {
return (
<Style.Wrapper>
<Typography variant="overline">- {route.pageKey}</Typography>
<RouteMenu route={route} />
</Style.Wrapper>
);
}}
>
{route.children?.map((childRoute) => (
<RouteTreeItem route={childRoute} key={childRoute.path}></RouteTreeItem>
))}
</TreeItem>
);
};
174 changes: 174 additions & 0 deletions portal-administration/src/components/Router/RouterEdit.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
import {
Button,
Card,
Icon,
TextField,
Typography,
} from "@equinor/eds-core-react";

import styled from "styled-components";

import { error_filled, info_circle } from "@equinor/eds-icons";
import { tokens } from "@equinor/eds-tokens";

import { useRouterConfigContext } from "../../context/RouterContext";
import { zodResolver } from "@hookform/resolvers/zod";
import { SubmitHandler, useForm } from "react-hook-form";
import { route } from "../../schema/route";
import { Route } from "../../types/router-config";
import { RouterRoot } from "./RouterRoot";

const Style = {
Wrapper: styled.div`
gap: 1rem;
display: flex;
padding: 1rem;
width: 100%;
flex-direction: column;
`,
RouterWrapper: styled.div`
gap: 0.5rem;
display: flex;
flex-direction: column;
`,
Content: styled.div`
padding: 1rem;
gap: 1rem;
display: flex;
flex-direction: column;
`,
Route: styled.div`
display: flex;
flex-direction: row;
`,
Form: styled.form`
display: flex;
flex-direction: column;
gap: 1rem;
`,
Routes: styled.span``,

Router: styled.span`
padding: 2rem;
min-width: 350px;
background-color: ${tokens.colors.ui.background__medium.hex};
display: flex;
flex-direction: column;
`,
};

export const RouterEdit = ({ portalName }: { portalName?: string }) => {
const { activeRoute, updateRoute, createNewRoute } = useRouterConfigContext();

const {
register,
handleSubmit,
formState: { errors, touchedFields },
} = useForm<Route>({
resolver: zodResolver(route),
values: activeRoute,

reValidateMode: "onChange",
});

const onSubmit: SubmitHandler<Route> = async (newRoute) => {
updateRoute(newRoute);
};

return (
<Style.Wrapper>
<Typography variant="h4">
{portalName
? `${portalName} - Routes Config`
: "Postal - Routes Config"}
</Typography>
<RouterRoot />
<form onSubmit={handleSubmit(onSubmit)} id="route">
<Card>
<Card.Header>
<Typography variant="h4">Edit Route</Typography>
<Icon data={info_circle} />
</Card.Header>
<Style.Content>
<TextField
id="id"
label="Route Id"
readOnly
value={activeRoute?.id}
/>
<TextField
{...register("path")}
id="path"
label="Route Path"
variant={errors.path && "error"}
helperText={errors.path?.message}
inputIcon={
errors.description && <Icon data={error_filled} title="Error" />
}
/>
<TextField
id="pageKey"
{...register("pageKey")}
label="Page Key"
variant={errors.pageKey && "error"}
helperText={errors.pageKey?.message}
inputIcon={
errors.description && <Icon data={error_filled} title="Error" />
}
/>
<TextField
rows={3}
multiline
{...register("description")}
id="description"
variant={errors.description && "error"}
helperText={errors.description?.message}
inputIcon={
errors.description && <Icon data={error_filled} title="Error" />
}
label="Description"
maxLength={501}
/>
</Style.Content>
<Card.Header>
<Typography variant="h4">Messages</Typography>
<Icon data={info_circle} />
</Card.Header>
<Card.Content>
<TextField
{...register("messages.errorMessage")}
id="errorMessage"
label="Error Message"
variant={errors.messages?.errorMessage && "error"}
helperText={errors.messages?.errorMessage?.message}
inputIcon={
errors.description && <Icon data={error_filled} title="Error" />
}
/>
</Card.Content>
<Card.Actions>
<Button
disabled={
!activeRoute ||
activeRoute?.id === "" ||
Object.keys(touchedFields).length <= 0
}
type="submit"
form="route"
>
Save Route
</Button>
<Button
variant="outlined"
onClick={() => {
createNewRoute();
}}
>
Add New route
</Button>
</Card.Actions>
</Card>
</form>
</Style.Wrapper>
);
};
72 changes: 72 additions & 0 deletions portal-administration/src/components/Router/RouterRoot.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import {
Button,
Card,
Icon,
TextField,
Typography,
} from "@equinor/eds-core-react";

import styled from "styled-components";

import { error_filled, info_circle } from "@equinor/eds-icons";

import { useRouterConfigContext } from "../../context/RouterContext";
import { zodResolver } from "@hookform/resolvers/zod";
import { SubmitHandler, useForm } from "react-hook-form";
import { RootInput, rootInput } from "../../schema/route";

const Style = {
Content: styled.div`
padding: 1rem;
gap: 1rem;
display: flex;
flex-direction: column;
`,
};

export const RouterRoot = () => {
const { root, updateRoot } = useRouterConfigContext();

const {
register,
handleSubmit,
formState: { errors },
} = useForm<RootInput>({
resolver: zodResolver(rootInput),
defaultValues: root,
reValidateMode: "onChange",
});

const onSubmit: SubmitHandler<RootInput> = async (root) => {
updateRoot(root.pageKey);
};

return (
<form onSubmit={handleSubmit(onSubmit)}>
<Card>
<Card.Header>
<Typography variant="h4">Edit Root</Typography>
<Icon data={info_circle} />
</Card.Header>
<Style.Content>
<TextField
{...register("pageKey")}
id="pageKey"
variant={errors.pageKey && "error"}
helperText={errors.pageKey?.message}
inputIcon={
errors.pageKey && <Icon data={error_filled} title="Error" />
}
label="Root Page Id"
/>
</Style.Content>

<Card.Actions>
<Button disabled={!errors} type="submit">
Save
</Button>
</Card.Actions>
</Card>
</form>
);
};
Loading

0 comments on commit 36aa2ca

Please sign in to comment.