GitHub - fc-micro-frontends/career-up at step12
REACT_APP_AUTH0_DOMAIN=dev-vcrmf0xuep020tri.us.auth0.com
REACT_APP_AUTH0_CLIENT_ID=27LLb4I9cIjiiQNSjbNIX9sQM1KECUfk
REACT_APP_AUTH0_CALLBACK_URL=http://localhost:3000
➜ pnpm i
➜ pnpm build
// career-up/apps/network/src/types.ts
import { type User } from "@auth0/auth0-spa-js";
export interface UserType extends User {}
export interface MyNetworkType {
connectionCount: number;
contactCount: number;
eventCount: number;
pageCount: number;
user: UserType;
}
export interface ConnectionType {
name: string;
picture: string | null;
role: string;
networkCount: number;
}
// career-up/apps/network/src/apis.ts
import { type ConnectionType, type MyNetworkType } from "./types";
export async function getMyNetwork(token: string): Promise<MyNetworkType> {
const res = await fetch("<http://localhost:4000/my-network>", {
headers: {
Authorization: `Bearer ${token}`,
},
});
return await res.json();
}
export async function getConnections(token: string): Promise<ConnectionType[]> {
const res = await fetch("<http://localhost:4000/connections>", {
headers: {
Authorization: `Bearer ${token}`,
},
});
return await res.json();
}
// career-up/apps/network/src/routes.tsx
import React from "react";
import { type RouteObject } from "react-router-dom";
import { AppRoutingManager } from "@career-up/shell-router";
import Auth0ClientProvider from "./providers/auth0-client-provider";
import { RecoilRoot } from "recoil";
**import Layout from "./components/layout";**
export const routes: RouteObject[] = [
{
path: "/",
element: (
<RecoilRoot>
<Auth0ClientProvider>
**<Layout>**
<AppRoutingManager type="app-network" />
**</Layout>**
</Auth0ClientProvider>
</RecoilRoot>
),
errorElement: <div>App Network Error</div>,
children: [
{
index: true,
element: <div className="network--text-9xl">network home</div>,
},
],
},
];
// career-up/apps/network/src/styles/f.css.ts
const prefix = "network--";
export const style = (classNames: string[]): string => {
return classNames.map((className) => `${prefix}${className}`).join(" ");
};
// career-up/apps/network/src/index.scss
@tailwind base;
@tailwind components;
@tailwind utilities;
html {
line-height: normal;
}
body {
font-family: Arial, Helvetica, sans-serif;
margin: 0;
padding: 0;
background-color: #f4f2ee;
}
img {
max-width: none;
}
button {
font-size: revert;
}
* {
box-sizing: revert;
}
h3,
p {
all: revert;
}
**.network--mx-w-1128px {
max-width: 1128px;
}
.network--w-225px {
width: 225px;
}
.network--w-879px {
width: 879px;
}**
// career-up/apps/network/src/components/layout.css.ts
import { style } from "../styles/f.css";
export const wrapper = style([
"flex",
"flex-row",
"gap-6",
"mx-auto",
"my-0",
"mx-w-1128px",
"p-4",
]);
export const left = style(["flex", "flex-col", "w-225px", "gap-2.5"]);
export const center = style(["flex", "flex-col", "w-879px", "gap-2.5"]);
// career-up/apps/network/src/components/layout.tsx
import React from "react";
import { wrapper, center, left } from "./layout.css";
import MyNetworkContainer from "../containers/my-network-container";
const Layout: React.FC<React.PropsWithChildren> = ({ children }) => {
return (
<div className={wrapper}>
<div className={left}>
<MyNetworkContainer />
</div>
<div className={center}>{children}</div>
</div>
);
};
export default Layout;
// career-up/apps/network/src/atoms.ts
import { atom } from "recoil";
import { type MyNetworkType } from "./types";
export const myNetworkAtom = atom<MyNetworkType | null>({
key: "my-network",
default: null,
});
// career-up/apps/network/src/containers/my-network-container.tsx
import React, { useCallback } from "react";
import { useRecoilState } from "recoil";
import { myNetworkAtom } from "../atoms";
import MyNetwork from "../components/my-network";
import useAuth0Client from "../hooks/use-auth0-client";
import { getMyNetwork } from "../apis";
const MyNetworkContainer: React.FC = () => {
const auth0Client = useAuth0Client();
const [myNetwork, setMyNetwork] = useRecoilState(myNetworkAtom);
const fetchMyNetwork = useCallback(async () => {
try {
const token = await auth0Client.getTokenSilently();
const myNetwork = await getMyNetwork(token);
setMyNetwork(myNetwork);
} catch (error) {
alert(error);
}
}, [auth0Client, setMyNetwork]);
return <MyNetwork myNetwork={myNetwork} fetchMyNetwork={fetchMyNetwork} />;
};
export default MyNetworkContainer;
// career-up/apps/network/src/components/my-network.css.ts
import { style } from "../styles/f.css";
export const topAreaTitle = style([
"text-base",
"font-bold",
"h-4",
"leading-4",
]);
export const topArea = style([
"flex",
"flex-col",
"bg-white",
"px-3",
"py-4",
"border-solid",
"border-b",
"border-slate-700",
"rounded-tr-lg",
"rounded-tl-lg",
"gap-2",
]);
export const topAreaLinks = style([
"flex",
"flex-col",
"bg-white",
"py-2",
"border-b",
]);
export const topAreaLink = [
style([
"flex",
"flex-row",
"text-base",
"text-gray-600",
"py-2",
"px-3",
"justify-between",
]),
"hover:" + style(["bg-gray-200", "cursor-pointer"]),
].join(" ");
export const topAreaLinkCount = style(["text-base", "text-gray-600"]);
export const img = style(["w-12"]);
export const name = style(["text-base", "font-bold"]);
export const email = style(["text-xs", "text-gray-600"]);
export const bottomArea = style([
"flex",
"flex-col",
"bg-white",
"px-3",
"py-4",
"rounded-br-lg",
"rounded-bl-lg",
"gap-2",
"justify-center",
"items-center",
]);
// career-up/apps/network/src/components/my-network.tsx
import React, { useEffect } from "react";
import * as css from "./my-network.css";
import { type MyNetworkType } from "../types";
interface MyNetworkProps {
myNetwork: MyNetworkType | null;
fetchMyNetwork: () => Promise<void>;
}
const MyNetwork: React.FC<MyNetworkProps> = ({ myNetwork, fetchMyNetwork }) => {
useEffect(() => {
fetchMyNetwork();
}, [fetchMyNetwork]);
if (myNetwork === null) {
return null;
}
const {
connectionCount,
contactCount,
eventCount,
pageCount,
user: { picture, name, email },
} = myNetwork;
return (
<div>
<div className={css.topArea}>
<span className={css.topAreaTitle}>인맥 관리</span>
</div>
<div className={css.topAreaLinks}>
<div className={css.topAreaLink}>
<div>1촌</div>
<div className={css.topAreaLinkCount}>{connectionCount}</div>
</div>
<div className={css.topAreaLink}>
<div>연락처</div>
<div className={css.topAreaLinkCount}>{contactCount}</div>
</div>
<div className={css.topAreaLink}>
<div>이벤트</div>
<div className={css.topAreaLinkCount}>{eventCount}</div>
</div>
<div className={css.topAreaLink}>
<div>페이지</div>
<div className={css.topAreaLinkCount}>{pageCount}</div>
</div>
</div>
<div className={css.bottomArea}>
<img className={css.img} src={picture} />
<div className={css.name}>{name}</div>
<div className={css.email}>{email}</div>
</div>
</div>
);
};
export default MyNetwork;
// career-up/apps/network/src/pages/page-home.tsx
import React from "react";
import ManageConnection from "../components/manage-connection";
import ConnectionsContainer from "../containers/connections-container";
const PageHome: React.FC = () => {
return (
<>
<ManageConnection />
<ConnectionsContainer />
</>
);
};
export default PageHome;
// career-up/apps/network/src/components/manage-connection.css.ts
import { style } from "../styles/f.css";
export const wrapper = style([
"flex",
"flex-row",
"bg-white",
"p-4",
"rounded-lg",
"justify-between",
"items-center",
]);