From df45d10da10079dee8a55b45347d3243546d1994 Mon Sep 17 00:00:00 2001 From: Mahmoud Moravej Date: Wed, 6 Dec 2023 15:04:17 -0500 Subject: [PATCH] add Individuals pages - show only --- app/@types/graphql/schema.ts | 258 +++++++++++++++-- app/entry.server.tsx | 22 +- app/models/user.ts | 3 + .../graphql/findManager.gql | 0 .../graphql/update.gql | 0 .../route.tsx | 2 +- .../graphql/query.gql | 11 + .../route.tsx | 271 ++++++++++++++++++ .../tests/route.test.tsx | 0 .../graphql/create.gql | 0 .../route.tsx | 0 .../graphql/query.gql | 15 - .../_dashboard.managers._index/route.tsx | 235 --------------- app/routes/auth.google.callback.tsx | 2 +- app/routes/auth.google.tsx | 2 +- app/routesData.tsx | 17 +- app/services/auth.strategies/google.ts | 25 +- .../graphql/getLoggedInUserInfo.gql | 9 + app/utils/graphql.ts | 17 ++ app/utils/index.ts | 1 + app/widgets/layout/sidenav.tsx | 2 +- remix.config.cjs | 8 + 22 files changed, 591 insertions(+), 309 deletions(-) rename app/routes/{_dashboard.managers.$id => _dashboard.individuals.$id.edit}/graphql/findManager.gql (100%) rename app/routes/{_dashboard.managers.$id => _dashboard.individuals.$id.edit}/graphql/update.gql (100%) rename app/routes/{_dashboard.managers.$id => _dashboard.individuals.$id.edit}/route.tsx (98%) create mode 100644 app/routes/_dashboard.individuals._index.($id)/graphql/query.gql create mode 100644 app/routes/_dashboard.individuals._index.($id)/route.tsx rename app/routes/{_dashboard.managers._index => _dashboard.individuals._index.($id)}/tests/route.test.tsx (100%) rename app/routes/{_dashboard.managers.new => _dashboard.individuals.new}/graphql/create.gql (100%) rename app/routes/{_dashboard.managers.new => _dashboard.individuals.new}/route.tsx (100%) delete mode 100644 app/routes/_dashboard.managers._index/graphql/query.gql delete mode 100644 app/routes/_dashboard.managers._index/route.tsx create mode 100644 app/services/auth.strategies/graphql/getLoggedInUserInfo.gql create mode 100644 app/utils/graphql.ts create mode 100644 app/utils/index.ts diff --git a/app/@types/graphql/schema.ts b/app/@types/graphql/schema.ts index 387ac94..104f3b6 100644 --- a/app/@types/graphql/schema.ts +++ b/app/@types/graphql/schema.ts @@ -17,6 +17,123 @@ export type Scalars = { Float: { input: number; output: number; } }; +export type Individual = { + __typename?: 'Individual'; + fullname?: Maybe; + handleGithub?: Maybe; + handleGoogle?: Maybe; + id: Scalars['Int']['output']; + isActive: Scalars['Boolean']['output']; + isManager: Scalars['Boolean']['output']; + jobLevelId?: Maybe; + jobTitle?: Maybe; + manager?: Maybe; + managerId?: Maybe; + organizationId: Scalars['Int']['output']; + reports: IndividualConnection; + userId?: Maybe; +}; + + +export type IndividualReportsArgs = { + after?: InputMaybe; + before?: InputMaybe; + first?: InputMaybe; + last?: InputMaybe; +}; + +/** The connection type for Individual. */ +export type IndividualConnection = { + __typename?: 'IndividualConnection'; + /** A list of edges. */ + edges?: Maybe>>; + /** A list of nodes. */ + nodes?: Maybe>>; + /** Information to aid in pagination. */ + pageInfo: PageInfo; +}; + +export type IndividualCreate = { + fullname?: InputMaybe; + handleGithub?: InputMaybe; + handleGoogle?: InputMaybe; + isActive: Scalars['Boolean']['input']; + isManager: Scalars['Boolean']['input']; + jobLevelId?: InputMaybe; + jobTitle?: InputMaybe; + managerId?: InputMaybe; + organizationId?: InputMaybe; + userId?: InputMaybe; +}; + +/** Autogenerated input type of IndividualCreate */ +export type IndividualCreateInput = { + /** A unique identifier for the client performing the mutation. */ + clientMutationId?: InputMaybe; + individualInput: IndividualCreate; +}; + +/** Autogenerated return type of IndividualCreate. */ +export type IndividualCreatePayload = { + __typename?: 'IndividualCreatePayload'; + /** A unique identifier for the client performing the mutation. */ + clientMutationId?: Maybe; + individual: Individual; +}; + +/** Autogenerated input type of IndividualDestroy */ +export type IndividualDestroyInput = { + /** A unique identifier for the client performing the mutation. */ + clientMutationId?: InputMaybe; + id: Scalars['ID']['input']; +}; + +/** Autogenerated return type of IndividualDestroy. */ +export type IndividualDestroyPayload = { + __typename?: 'IndividualDestroyPayload'; + /** A unique identifier for the client performing the mutation. */ + clientMutationId?: Maybe; + individual: Individual; +}; + +/** An edge in a connection. */ +export type IndividualEdge = { + __typename?: 'IndividualEdge'; + /** A cursor for use in pagination. */ + cursor: Scalars['String']['output']; + /** The item at the end of the edge. */ + node?: Maybe; +}; + +export type IndividualUpdate = { + fullname?: InputMaybe; + handleGithub?: InputMaybe; + handleGoogle?: InputMaybe; + isActive?: InputMaybe; + isManager?: InputMaybe; + jobLevelId?: InputMaybe; + jobTitle?: InputMaybe; + managerId?: InputMaybe; + organizationId?: InputMaybe; + userId?: InputMaybe; +}; + +/** Autogenerated input type of IndividualUpdate */ +export type IndividualUpdateInput = { + /** A unique identifier for the client performing the mutation. */ + clientMutationId?: InputMaybe; + id: Scalars['ID']['input']; + individualInput: IndividualUpdate; +}; + +/** Autogenerated return type of IndividualUpdate. */ +export type IndividualUpdatePayload = { + __typename?: 'IndividualUpdatePayload'; + /** A unique identifier for the client performing the mutation. */ + clientMutationId?: Maybe; + individual: Individual; +}; + export type Manager = { __typename?: 'Manager'; Id: Scalars['Int']['output']; @@ -90,6 +207,12 @@ export type ManagerUpdatePayload = { export type Mutation = { __typename?: 'Mutation'; + /** Creates a new individual */ + individualCreate?: Maybe; + /** remove an existing individual by id */ + individualDestroy?: Maybe; + /** Update an existing individual by id */ + individualUpdate?: Maybe; /** Creates a new manager */ managerCreate?: Maybe; /** Updates a manager by id */ @@ -101,6 +224,21 @@ export type Mutation = { }; +export type MutationIndividualCreateArgs = { + input: IndividualCreateInput; +}; + + +export type MutationIndividualDestroyArgs = { + input: IndividualDestroyInput; +}; + + +export type MutationIndividualUpdateArgs = { + input: IndividualUpdateInput; +}; + + export type MutationManagerCreateArgs = { input: ManagerCreateInput; }; @@ -149,10 +287,16 @@ export enum PerformanceCategory { export type Query = { __typename?: 'Query'; + /** Returns an individual */ + individual: Individual; + /** Returns a list of individuals */ + individuals: IndividualConnection; /** Returns a manager */ manager: Manager; /** Returns a list of managers */ managers: ManagerConnection; + /** Returns logged in user details */ + myInfo: UserInfo; /** Returns a report */ report: Report; /** Returns a list of reports */ @@ -160,6 +304,21 @@ export type Query = { }; +export type QueryIndividualArgs = { + id: Scalars['ID']['input']; +}; + + +export type QueryIndividualsArgs = { + after?: InputMaybe; + before?: InputMaybe; + first?: InputMaybe; + last?: InputMaybe; + managerId?: InputMaybe; + orderBy?: InputMaybe>; +}; + + export type QueryManagerArgs = { id: Scalars['ID']['input']; }; @@ -253,6 +412,12 @@ export type ReportUpdatePayload = { report: Report; }; +export type UserInfo = { + __typename?: 'UserInfo'; + Individual?: Maybe; + UserId: Scalars['Int']['output']; +}; + export type FindManagerQueryVariables = Exact<{ id: Scalars['ID']['input']; }>; @@ -269,10 +434,12 @@ export type UpdateManagerMutationVariables = Exact<{ export type UpdateManagerMutation = { __typename?: 'Mutation', managerUpdate?: { __typename?: 'ManagerUpdatePayload', manager: { __typename?: 'Manager', Name: string, Id: number } } | null }; -export type ManagersQueryVariables = Exact<{ [key: string]: never; }>; +export type IndividualsQueryVariables = Exact<{ + managerId?: InputMaybe; +}>; -export type ManagersQuery = { __typename?: 'Query', managers: { __typename?: 'ManagerConnection', nodes?: Array<{ __typename?: 'Manager', id: number, name: string, reports: { __typename?: 'ReportConnection', nodes?: Array<{ __typename?: 'Report', id: number, name: string } | null> | null } } | null> | null } }; +export type IndividualsQuery = { __typename?: 'Query', individuals: { __typename?: 'IndividualConnection', nodes?: Array<{ __typename?: 'Individual', id: number, fullname?: string | null, jobTitle?: string | null, jobLevelId?: string | null, isManager: boolean } | null> | null } }; export type CreateManagerMutationVariables = Exact<{ name: Scalars['String']['input']; @@ -282,6 +449,11 @@ export type CreateManagerMutationVariables = Exact<{ export type CreateManagerMutation = { __typename?: 'Mutation', managerCreate?: { __typename?: 'ManagerCreatePayload', manager: { __typename?: 'Manager', Name: string, Id: number } } | null }; +export type GetLoggedInUserInfoQueryVariables = Exact<{ [key: string]: never; }>; + + +export type GetLoggedInUserInfoQuery = { __typename?: 'Query', myInfo: { __typename?: 'UserInfo', UserId: number, Individual?: { __typename?: 'Individual', id: number, isManager: boolean } | null } }; + export const FindManagerDocument = gql` query findManager($id: ID!) { @@ -357,49 +529,47 @@ export function useUpdateManagerMutation(baseOptions?: Apollo.MutationHookOption export type UpdateManagerMutationHookResult = ReturnType; export type UpdateManagerMutationResult = Apollo.MutationResult; export type UpdateManagerMutationOptions = Apollo.BaseMutationOptions; -export const ManagersDocument = gql` - query managers { - managers(first: 10, orderBy: {field: "name", direction: "ASC"}) { +export const IndividualsDocument = gql` + query individuals($managerId: ID) { + individuals(managerId: $managerId) { nodes { - id: Id - name: Name - reports: Reports { - nodes { - id: Id - name: Name - } - } + id + fullname + jobTitle + jobLevelId + isManager } } } `; /** - * __useManagersQuery__ + * __useIndividualsQuery__ * - * To run a query within a React component, call `useManagersQuery` and pass it any options that fit your needs. - * When your component renders, `useManagersQuery` returns an object from Apollo Client that contains loading, error, and data properties + * To run a query within a React component, call `useIndividualsQuery` and pass it any options that fit your needs. + * When your component renders, `useIndividualsQuery` returns an object from Apollo Client that contains loading, error, and data properties * you can use to render your UI. * * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; * * @example - * const { data, loading, error } = useManagersQuery({ + * const { data, loading, error } = useIndividualsQuery({ * variables: { + * managerId: // value for 'managerId' * }, * }); */ -export function useManagersQuery(baseOptions?: Apollo.QueryHookOptions) { +export function useIndividualsQuery(baseOptions?: Apollo.QueryHookOptions) { const options = {...defaultOptions, ...baseOptions} - return Apollo.useQuery(ManagersDocument, options); + return Apollo.useQuery(IndividualsDocument, options); } -export function useManagersLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { +export function useIndividualsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { const options = {...defaultOptions, ...baseOptions} - return Apollo.useLazyQuery(ManagersDocument, options); + return Apollo.useLazyQuery(IndividualsDocument, options); } -export type ManagersQueryHookResult = ReturnType; -export type ManagersLazyQueryHookResult = ReturnType; -export type ManagersQueryResult = Apollo.QueryResult; +export type IndividualsQueryHookResult = ReturnType; +export type IndividualsLazyQueryHookResult = ReturnType; +export type IndividualsQueryResult = Apollo.QueryResult; export const CreateManagerDocument = gql` mutation createManager($name: String!, $id: Int!) { managerCreate(input: {managerInput: {Name: $name, Id: $id}}) { @@ -436,4 +606,42 @@ export function useCreateManagerMutation(baseOptions?: Apollo.MutationHookOption } export type CreateManagerMutationHookResult = ReturnType; export type CreateManagerMutationResult = Apollo.MutationResult; -export type CreateManagerMutationOptions = Apollo.BaseMutationOptions; \ No newline at end of file +export type CreateManagerMutationOptions = Apollo.BaseMutationOptions; +export const GetLoggedInUserInfoDocument = gql` + query getLoggedInUserInfo { + myInfo { + UserId + Individual { + id + isManager + } + } +} + `; + +/** + * __useGetLoggedInUserInfoQuery__ + * + * To run a query within a React component, call `useGetLoggedInUserInfoQuery` and pass it any options that fit your needs. + * When your component renders, `useGetLoggedInUserInfoQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetLoggedInUserInfoQuery({ + * variables: { + * }, + * }); + */ +export function useGetLoggedInUserInfoQuery(baseOptions?: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(GetLoggedInUserInfoDocument, options); + } +export function useGetLoggedInUserInfoLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(GetLoggedInUserInfoDocument, options); + } +export type GetLoggedInUserInfoQueryHookResult = ReturnType; +export type GetLoggedInUserInfoLazyQueryHookResult = ReturnType; +export type GetLoggedInUserInfoQueryResult = Apollo.QueryResult; \ No newline at end of file diff --git a/app/entry.server.tsx b/app/entry.server.tsx index 92ee524..0f98562 100644 --- a/app/entry.server.tsx +++ b/app/entry.server.tsx @@ -12,15 +12,11 @@ import { RemixServer } from "@remix-run/react"; import isbot from "isbot"; import { renderToPipeableStream } from "react-dom/server"; -import { - ApolloProvider, - ApolloClient, - InMemoryCache, - createHttpLink, -} from "@apollo/client"; +import { ApolloProvider } from "@apollo/client"; import { getDataFromTree } from "@apollo/client/react/ssr"; import { authenticator } from "./services/auth.server"; import type { ReactElement } from "react"; +import * as utils from "./utils"; const ABORT_DELAY = 5_000; @@ -178,17 +174,5 @@ async function wrapRemixServerWithApollo( async function getApolloClient(request: Request) { let user = await authenticator.isAuthenticated(request); - const client = new ApolloClient({ - ssrMode: true, - cache: new InMemoryCache(), - link: createHttpLink({ - uri: process.env.GRAPHQL_SCHEMA_URL || "GRAPHQL_SCHEMA_URL IS NOT SET", - headers: { - ...Object.fromEntries(request.headers), - Authorization: `Bearer ${user?.jwt_token ?? "ERROR TOKEN!"}`, - }, - credentials: request.credentials ?? "include", // or "same-origin" if your backend server is the same domain - }), - }); - return client; + return utils.getApolloClient(request, user?.jwt_token); } diff --git a/app/models/user.ts b/app/models/user.ts index 47d0b39..8545005 100644 --- a/app/models/user.ts +++ b/app/models/user.ts @@ -2,4 +2,7 @@ export type User = { email: string; jwt_token: string; name: string; + user_id: number; + individual_id?: number; + is_manager?: boolean; }; diff --git a/app/routes/_dashboard.managers.$id/graphql/findManager.gql b/app/routes/_dashboard.individuals.$id.edit/graphql/findManager.gql similarity index 100% rename from app/routes/_dashboard.managers.$id/graphql/findManager.gql rename to app/routes/_dashboard.individuals.$id.edit/graphql/findManager.gql diff --git a/app/routes/_dashboard.managers.$id/graphql/update.gql b/app/routes/_dashboard.individuals.$id.edit/graphql/update.gql similarity index 100% rename from app/routes/_dashboard.managers.$id/graphql/update.gql rename to app/routes/_dashboard.individuals.$id.edit/graphql/update.gql diff --git a/app/routes/_dashboard.managers.$id/route.tsx b/app/routes/_dashboard.individuals.$id.edit/route.tsx similarity index 98% rename from app/routes/_dashboard.managers.$id/route.tsx rename to app/routes/_dashboard.individuals.$id.edit/route.tsx index 699a501..71fa103 100644 --- a/app/routes/_dashboard.managers.$id/route.tsx +++ b/app/routes/_dashboard.individuals.$id.edit/route.tsx @@ -84,7 +84,7 @@ export default function ManagerEdit() { className="mt-6" fullWidth onClick={() => { - nav("/managers"); + nav("/individuals"); }} > Goto Managers diff --git a/app/routes/_dashboard.individuals._index.($id)/graphql/query.gql b/app/routes/_dashboard.individuals._index.($id)/graphql/query.gql new file mode 100644 index 0000000..43bf8c9 --- /dev/null +++ b/app/routes/_dashboard.individuals._index.($id)/graphql/query.gql @@ -0,0 +1,11 @@ +query individuals($managerId: ID) { + individuals(managerId: $managerId) { + nodes { + id + fullname + jobTitle + jobLevelId + isManager + } + } +} diff --git a/app/routes/_dashboard.individuals._index.($id)/route.tsx b/app/routes/_dashboard.individuals._index.($id)/route.tsx new file mode 100644 index 0000000..531b3cb --- /dev/null +++ b/app/routes/_dashboard.individuals._index.($id)/route.tsx @@ -0,0 +1,271 @@ +import { useIndividualsQuery } from "@app-types/graphql"; +import { MagnifyingGlassIcon } from "@heroicons/react/24/outline"; +import { + PencilIcon, + UserPlusIcon, + HomeIcon, + MagnifyingGlassCircleIcon, +} from "@heroicons/react/24/solid"; +import { + Card, + CardHeader, + Input, + Typography, + Button, + CardBody, + Chip, + CardFooter, + Tabs, + TabsHeader, + Tab, + Avatar, + IconButton, + Tooltip, +} from "@material-tailwind/react"; +import { LoaderFunction, redirect } from "@remix-run/node"; +import { Link, useLoaderData, useNavigate, useParams } from "@remix-run/react"; +import { User } from "~/models/user"; +import { authenticator } from "~/services/auth.server"; + +const TABS = [ + { + label: "All", + value: "all", + }, + { + label: "Monitored", + value: "monitored", + }, + { + label: "Unmonitored", + value: "unmonitored", + }, +]; + +const TABLE_HEAD = ["Name", "Level", "Role", ""]; + +export let loader: LoaderFunction = async ({ request }) => { + //we should completely change the following appraoch + let user = await authenticator.isAuthenticated(request); + if (!user) return redirect("/login"); + else return { user }; +}; + +function useUser() { + const data = useLoaderData<{ user?: User }>(); + return data.user; +} + +export default function Individuals() { + let { id: managerId } = useParams(); + const user = useUser(); + + console.log("user?.individual_id", user); + if (managerId == "myteam" && user?.individual_id != null) { + managerId = user?.individual_id.toString(); + } + + const { data, loading, error } = useIndividualsQuery({ + variables: { + managerId: managerId ?? null, + }, + fetchPolicy: "network-only", + }); + const navigate = useNavigate(); + + if (loading) return

Loading...

; + if (error) return

{JSON.stringify(error)}

; + if (data?.individuals?.nodes == null) return

no data

; + + const individuals = data.individuals.nodes.map((node) => + node == null + ? {} + : { + id: node.id, + name: node.fullname, + jobTitle: node.jobTitle, + jobLevelId: node.jobLevelId, + isManager: node.isManager, + }, + ); + + return ( + + +
+
+ + People + + + See information about all people + +
+
+ + + + +
+
+
+ + + {TABS.map(({ label, value }) => ( + +   {label}   + + ))} + + +
+ } + crossOrigin={undefined} + /> +
+
+
+ + + + + {TABLE_HEAD.map((head) => ( + + ))} + + + + {individuals.map( + ({ name, id, jobTitle, isManager, jobLevelId }, index) => { + const isLast = index === individuals.length - 1; + const classes = isLast + ? "p-4" + : "p-4 border-b border-blue-gray-50"; + + return ( + + + + + + + + ); + }, + )} + +
+ + {head} + +
+
+ +
+ + {isManager ? ( + + {name} + + + ) : ( + name + )} + + + {jobTitle} + +
+
+
+
+ + {jobLevelId} + + + {jobLevelId} + +
+
+
+ +
+
+ + + + + + + +
+
+ + + Page 1 of 10 + +
+ + +
+
+
+ ); +} diff --git a/app/routes/_dashboard.managers._index/tests/route.test.tsx b/app/routes/_dashboard.individuals._index.($id)/tests/route.test.tsx similarity index 100% rename from app/routes/_dashboard.managers._index/tests/route.test.tsx rename to app/routes/_dashboard.individuals._index.($id)/tests/route.test.tsx diff --git a/app/routes/_dashboard.managers.new/graphql/create.gql b/app/routes/_dashboard.individuals.new/graphql/create.gql similarity index 100% rename from app/routes/_dashboard.managers.new/graphql/create.gql rename to app/routes/_dashboard.individuals.new/graphql/create.gql diff --git a/app/routes/_dashboard.managers.new/route.tsx b/app/routes/_dashboard.individuals.new/route.tsx similarity index 100% rename from app/routes/_dashboard.managers.new/route.tsx rename to app/routes/_dashboard.individuals.new/route.tsx diff --git a/app/routes/_dashboard.managers._index/graphql/query.gql b/app/routes/_dashboard.managers._index/graphql/query.gql deleted file mode 100644 index dc231e4..0000000 --- a/app/routes/_dashboard.managers._index/graphql/query.gql +++ /dev/null @@ -1,15 +0,0 @@ -query managers { - # managers(first: 10, order: { name: ASC }) { ## FOR .NET CORE version - managers(first: 10, orderBy: { field: "name", direction: "ASC" }) { - nodes { - id: Id - name: Name - reports: Reports { - nodes { - id: Id - name: Name - } - } - } - } -} diff --git a/app/routes/_dashboard.managers._index/route.tsx b/app/routes/_dashboard.managers._index/route.tsx deleted file mode 100644 index 98df6aa..0000000 --- a/app/routes/_dashboard.managers._index/route.tsx +++ /dev/null @@ -1,235 +0,0 @@ -import { useManagersQuery } from "@app-types/graphql"; -import { MagnifyingGlassIcon } from "@heroicons/react/24/outline"; -import { PencilIcon, UserPlusIcon, HomeIcon } from "@heroicons/react/24/solid"; -import { - Card, - CardHeader, - Input, - Typography, - Button, - CardBody, - Chip, - CardFooter, - Tabs, - TabsHeader, - Tab, - Avatar, - IconButton, - Tooltip, -} from "@material-tailwind/react"; -import { LoaderFunction, redirect } from "@remix-run/node"; -import { Link, useNavigate } from "@remix-run/react"; -import { authenticator } from "~/services/auth.server"; - -const TABS = [ - { - label: "All", - value: "all", - }, - { - label: "Monitored", - value: "monitored", - }, - { - label: "Unmonitored", - value: "unmonitored", - }, -]; - -const TABLE_HEAD = ["Member", "Function", "Status", "Employed", ""]; - -export let loader: LoaderFunction = async ({ request }) => { - //we should completely change the following appraoch - let isAllowed = await authenticator.isAuthenticated(request); - if (!isAllowed) return redirect("/login"); - else return {}; -}; - -export default function Managers() { - const { data, loading, error } = useManagersQuery({ - fetchPolicy: "network-only", - }); - const navigate = useNavigate(); - - if (loading) return

Loading...

; - if (error) return

{JSON.stringify(error)}

; - if (data?.managers?.nodes == null) return

no data

; - - const managers = data.managers.nodes.map((node) => ({ - name: node?.name, - id: node?.id, - })); - - return ( - - -
-
- - Members list - - - See information about all members - -
-
- - - - -
-
-
- - - {TABS.map(({ label, value }) => ( - -   {label}   - - ))} - - -
- } - crossOrigin={undefined} - /> -
-
-
- - - - - {TABLE_HEAD.map((head) => ( - - ))} - - - - {managers.map(({ name, id }, index) => { - const isLast = index === managers.length - 1; - const classes = isLast - ? "p-4" - : "p-4 border-b border-blue-gray-50"; - - return ( - - - - - - - - ); - })} - -
- - {head} - -
-
- -
- - {name} - - - {"TODO"} - -
-
-
-
- - {"TODO"} - - - {"TODO"} - -
-
-
- -
-
- - {"TODO"} - - - - - - - - - -
-
- - - Page 1 of 10 - -
- - -
-
-
- ); -} diff --git a/app/routes/auth.google.callback.tsx b/app/routes/auth.google.callback.tsx index 3a88030..8747fa3 100644 --- a/app/routes/auth.google.callback.tsx +++ b/app/routes/auth.google.callback.tsx @@ -3,7 +3,7 @@ import { authenticator } from "~/services/auth.server"; export let loader = ({ request }: LoaderFunctionArgs) => { return authenticator.authenticate("google", request, { - successRedirect: "/managers", + successRedirect: "/individuals", failureRedirect: "/login", }); }; diff --git a/app/routes/auth.google.tsx b/app/routes/auth.google.tsx index 2bbe541..21f50e4 100644 --- a/app/routes/auth.google.tsx +++ b/app/routes/auth.google.tsx @@ -5,6 +5,6 @@ import { authenticator } from "~/services/auth.server"; export async function action({ request }: ActionFunctionArgs) { return authenticator.authenticate("google", request, { - successRedirect: "/managers", + successRedirect: "/individuals", }); } diff --git a/app/routesData.tsx b/app/routesData.tsx index a256853..b5d5f60 100644 --- a/app/routesData.tsx +++ b/app/routesData.tsx @@ -33,16 +33,15 @@ export const routes: RouteData[] = [ name: "Home", path: "/", }, - { - icon: , - name: "Managers", - path: "/managers", - }, - { icon: , name: "My team", - path: "/managers/team", + path: "/individuals/myteam", + }, + { + icon: , + name: "Organization", + path: "/individuals", }, { icon: , @@ -203,8 +202,8 @@ export const siteRoutes: siteRouteType[] = [ path: "/", }, { - name: "profile", - path: "/", + name: "dashboard", + path: "/individuals", }, { name: "Sign In", diff --git a/app/services/auth.strategies/google.ts b/app/services/auth.strategies/google.ts index 29daeb7..15c92df 100644 --- a/app/services/auth.strategies/google.ts +++ b/app/services/auth.strategies/google.ts @@ -1,5 +1,10 @@ +import { + GetLoggedInUserInfoDocument, + GetLoggedInUserInfoQuery, +} from "@app-types/graphql"; import { GoogleStrategy } from "remix-auth-google"; import type { User } from "~/models/user"; +import { getApolloClient } from "~/utils"; export let googleStrategy = new GoogleStrategy( { @@ -7,13 +12,29 @@ export let googleStrategy = new GoogleStrategy( clientSecret: process.env.GOOGLE_CLIENT_SECRET ?? "", callbackURL: "/auth/google/callback", }, - async ({ accessToken, refreshToken, extraParams, profile }) => { + async ({ accessToken, refreshToken, extraParams, profile, request }) => { // Get the user data from your DB or API using the tokens and profile + const jwt_token = extraParams.id_token; + + const client = getApolloClient(request, jwt_token); + const result = await client.query({ + query: GetLoggedInUserInfoDocument, + fetchPolicy: "network-only", + }); + + const myInfo = result.data?.myInfo; + if (myInfo === undefined) + throw new Error("error fetching loggined in usuer info"); + + const individual = myInfo?.Individual; return { email: profile.emails[0].value, - jwt_token: extraParams.id_token, + jwt_token: jwt_token, name: profile.displayName, + individual_id: individual?.id, + user_id: myInfo.UserId, + is_manager: individual?.isManager, } as User; }, ); diff --git a/app/services/auth.strategies/graphql/getLoggedInUserInfo.gql b/app/services/auth.strategies/graphql/getLoggedInUserInfo.gql new file mode 100644 index 0000000..f3a62fc --- /dev/null +++ b/app/services/auth.strategies/graphql/getLoggedInUserInfo.gql @@ -0,0 +1,9 @@ +query getLoggedInUserInfo { + myInfo { + UserId + Individual { + id + isManager + } + } +} diff --git a/app/utils/graphql.ts b/app/utils/graphql.ts new file mode 100644 index 0000000..4476f55 --- /dev/null +++ b/app/utils/graphql.ts @@ -0,0 +1,17 @@ +import { ApolloClient, InMemoryCache, createHttpLink } from "@apollo/client"; + +export function getApolloClient(request: Request, token: string | undefined) { + const client = new ApolloClient({ + ssrMode: true, + cache: new InMemoryCache(), + link: createHttpLink({ + uri: process.env.GRAPHQL_SCHEMA_URL || "GRAPHQL_SCHEMA_URL IS NOT SET", + headers: { + ...Object.fromEntries(request.headers), + Authorization: `Bearer ${token ?? "ERROR TOKEN!"}`, + }, + credentials: request.credentials ?? "include", // or "same-origin" if your backend server is the same domain + }), + }); + return client; +} diff --git a/app/utils/index.ts b/app/utils/index.ts new file mode 100644 index 0000000..f957b03 --- /dev/null +++ b/app/utils/index.ts @@ -0,0 +1 @@ +export * from "./graphql"; diff --git a/app/widgets/layout/sidenav.tsx b/app/widgets/layout/sidenav.tsx index 702f530..2b00a5e 100644 --- a/app/widgets/layout/sidenav.tsx +++ b/app/widgets/layout/sidenav.tsx @@ -80,7 +80,7 @@ export function Sidenav({ )} {pages.map(({ icon, name, path }) => (
  • - + {({ isActive }) => (