From 483a7186294461bea662d20ab7a94b69ef8aab81 Mon Sep 17 00:00:00 2001
From: hobbescodes <87732294+hobbescodes@users.noreply.github.com>
Date: Fri, 27 Dec 2024 13:44:41 -0600
Subject: [PATCH 01/72] refactor(auth): mock user ID temporarily
---
.env.local.template | 4 ++++
src/lib/config/env.config.ts | 3 +++
src/lib/hooks/useAuth.tsx | 5 ++++-
3 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/.env.local.template b/.env.local.template
index ba7796d69..3f0cf5d1a 100644
--- a/.env.local.template
+++ b/.env.local.template
@@ -5,3 +5,7 @@ WALLETCONNECT_PROJECT_ID=""
AUTH_KEYCLOAK_SECRET=""
# NB: an auth secret can be generated and injected automatically with `npx auth`, see https://cli.authjs.dev
AUTH_SECRET=""
+
+# NB: mocked user ID from locally seeded database.
+# TODO: remove once keycloak / hidra are synced with database
+NEXT_PUBLIC_MOCK_USER_ID=""
diff --git a/src/lib/config/env.config.ts b/src/lib/config/env.config.ts
index 9df00e351..564e83b1f 100644
--- a/src/lib/config/env.config.ts
+++ b/src/lib/config/env.config.ts
@@ -5,3 +5,6 @@ export const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL;
// web3
export const WALLETCONNECT_PROJECT_ID = process.env.WALLETCONNECT_PROJECT_ID;
+
+// TODO: remove once keycloak / hidra are synced with database
+export const MOCK_USER_ID = process.env.NEXT_PUBLIC_MOCK_USER_ID;
diff --git a/src/lib/hooks/useAuth.tsx b/src/lib/hooks/useAuth.tsx
index 0c2b5d571..26d52a06f 100644
--- a/src/lib/hooks/useAuth.tsx
+++ b/src/lib/hooks/useAuth.tsx
@@ -1,5 +1,7 @@
import { useSession } from "next-auth/react";
+import { MOCK_USER_ID } from "lib/config";
+
/**
* Access authentication state and user data.
*/
@@ -9,7 +11,8 @@ const useAuth = () => {
return {
isAuthenticated: status === "authenticated",
isLoading: status === "loading",
- user: data?.user,
+ // ! NB: mock user ID from seeded database until we sync with hidra
+ user: { ...data?.user, id: MOCK_USER_ID },
expiresAt: data?.expires,
update,
};
From ff60aa6263550e75d62d3ff5e8a1c4a251f61791 Mon Sep 17 00:00:00 2001
From: hobbescodes <87732294+hobbescodes@users.noreply.github.com>
Date: Fri, 27 Dec 2024 21:57:35 -0600
Subject: [PATCH 02/72] feature(dashboard): query for feedback aggregate
---
.../dashboard/Aggregate/Aggregate.tsx | 6 --
.../dashboard/DashboardPage/DashboardPage.tsx | 13 ++++-
src/generated/graphql.ts | 56 +++++++++++++++++++
.../queries/dashboardAggregates.query.graphql | 13 +++++
4 files changed, 81 insertions(+), 7 deletions(-)
create mode 100644 src/lib/graphql/queries/dashboardAggregates.query.graphql
diff --git a/src/components/dashboard/Aggregate/Aggregate.tsx b/src/components/dashboard/Aggregate/Aggregate.tsx
index 88381aafd..4fe546340 100644
--- a/src/components/dashboard/Aggregate/Aggregate.tsx
+++ b/src/components/dashboard/Aggregate/Aggregate.tsx
@@ -44,12 +44,6 @@ const Aggregate = ({ title, value, icon, isLoaded = true, isError }: Props) => (
{isError ? "Error" : value}
-
-
-
- {isError ? "Error" : "+4.2069% from last month"}
-
-
);
diff --git a/src/components/dashboard/DashboardPage/DashboardPage.tsx b/src/components/dashboard/DashboardPage/DashboardPage.tsx
index ed009ac7c..013b9f122 100644
--- a/src/components/dashboard/DashboardPage/DashboardPage.tsx
+++ b/src/components/dashboard/DashboardPage/DashboardPage.tsx
@@ -10,6 +10,7 @@ import { LuPlusCircle } from "react-icons/lu";
import { Aggregate, Feedback, PinnedOrganizations } from "components/dashboard";
import { Page } from "components/layout";
+import { useDashboardAggregatesQuery } from "generated/graphql";
import { app } from "lib/config";
import { useAuth, useDataState } from "lib/hooks";
@@ -20,10 +21,20 @@ const DashboardPage = () => {
const { user } = useAuth(),
{ isLoading, isError } = useDataState({ timeout: 400 });
+ const { data: feedbackCount } = useDashboardAggregatesQuery(
+ {
+ userId: user?.id!,
+ },
+ {
+ enabled: !!user,
+ select: (data) => data?.posts?.totalCount,
+ }
+ );
+
const aggregates = [
{
title: app.dashboardPage.aggregates.totalFeedback.title,
- value: "12,345",
+ value: feedbackCount ?? 0,
icon: HiOutlineChatBubbleLeftRight,
},
{
diff --git a/src/generated/graphql.ts b/src/generated/graphql.ts
index a02477f61..fd80a255a 100644
--- a/src/generated/graphql.ts
+++ b/src/generated/graphql.ts
@@ -3287,6 +3287,13 @@ export type UpvotePostMutationVariables = Exact<{
export type UpvotePostMutation = { __typename?: 'Mutation', createUpvote?: { __typename?: 'CreateUpvotePayload', clientMutationId?: string | null } | null };
+export type DashboardAggregatesQueryVariables = Exact<{
+ userId: Scalars['UUID']['input'];
+}>;
+
+
+export type DashboardAggregatesQuery = { __typename?: 'Query', posts?: { __typename?: 'PostConnection', totalCount: number } | null };
+
export type OrganizationQueryVariables = Exact<{
slug: Scalars['String']['input'];
}>;
@@ -3478,6 +3485,55 @@ export const useUpvotePostMutation = <
}
)};
+export const DashboardAggregatesDocument = `
+ query DashboardAggregates($userId: UUID!) {
+ posts(
+ filter: {project: {organization: {userOrganizations: {some: {userId: {equalTo: $userId}}}}}}
+ ) {
+ totalCount
+ }
+}
+ `;
+
+export const useDashboardAggregatesQuery = <
+ TData = DashboardAggregatesQuery,
+ TError = unknown
+ >(
+ variables: DashboardAggregatesQueryVariables,
+ options?: Omit, 'queryKey'> & { queryKey?: UseQueryOptions['queryKey'] }
+ ) => {
+
+ return useQuery(
+ {
+ queryKey: ['DashboardAggregates', variables],
+ queryFn: useGraphqlClient(DashboardAggregatesDocument).bind(null, variables),
+ ...options
+ }
+ )};
+
+useDashboardAggregatesQuery.getKey = (variables: DashboardAggregatesQueryVariables) => ['DashboardAggregates', variables];
+
+export const useInfiniteDashboardAggregatesQuery = <
+ TData = InfiniteData,
+ TError = unknown
+ >(
+ variables: DashboardAggregatesQueryVariables,
+ options: Omit, 'queryKey'> & { queryKey?: UseInfiniteQueryOptions['queryKey'] }
+ ) => {
+ const query = useGraphqlClient(DashboardAggregatesDocument)
+ return useInfiniteQuery(
+ (() => {
+ const { queryKey: optionsQueryKey, ...restOptions } = options;
+ return {
+ queryKey: optionsQueryKey ?? ['DashboardAggregates.infinite', variables],
+ queryFn: (metaData) => query({...variables, ...(metaData.pageParam ?? {})}),
+ ...restOptions
+ }
+ })()
+ )};
+
+useInfiniteDashboardAggregatesQuery.getKey = (variables: DashboardAggregatesQueryVariables) => ['DashboardAggregates.infinite', variables];
+
export const OrganizationDocument = `
query Organization($slug: String!) {
organizationBySlug(slug: $slug) {
diff --git a/src/lib/graphql/queries/dashboardAggregates.query.graphql b/src/lib/graphql/queries/dashboardAggregates.query.graphql
new file mode 100644
index 000000000..05277b430
--- /dev/null
+++ b/src/lib/graphql/queries/dashboardAggregates.query.graphql
@@ -0,0 +1,13 @@
+query DashboardAggregates($userId: UUID!) {
+ posts(
+ filter: {
+ project: {
+ organization: {
+ userOrganizations: { some: { userId: { equalTo: $userId } } }
+ }
+ }
+ }
+ ) {
+ totalCount
+ }
+}
From c1d29a5247a0f2e0ecdbb149e763fc4aca1bab55 Mon Sep 17 00:00:00 2001
From: hobbescodes <87732294+hobbescodes@users.noreply.github.com>
Date: Fri, 27 Dec 2024 22:38:31 -0600
Subject: [PATCH 03/72] feature(dashboard): query for active users aggregate
---
.../dashboard/DashboardPage/DashboardPage.tsx | 11 +++++++----
src/generated/graphql.ts | 7 ++++++-
.../queries/dashboardAggregates.query.graphql | 14 ++++++++++++++
3 files changed, 27 insertions(+), 5 deletions(-)
diff --git a/src/components/dashboard/DashboardPage/DashboardPage.tsx b/src/components/dashboard/DashboardPage/DashboardPage.tsx
index 013b9f122..c50a5b2ac 100644
--- a/src/components/dashboard/DashboardPage/DashboardPage.tsx
+++ b/src/components/dashboard/DashboardPage/DashboardPage.tsx
@@ -21,25 +21,28 @@ const DashboardPage = () => {
const { user } = useAuth(),
{ isLoading, isError } = useDataState({ timeout: 400 });
- const { data: feedbackCount } = useDashboardAggregatesQuery(
+ const { data: dashboardAggregates } = useDashboardAggregatesQuery(
{
userId: user?.id!,
},
{
enabled: !!user,
- select: (data) => data?.posts?.totalCount,
+ select: (data) => ({
+ totalFeedback: data?.posts?.totalCount,
+ totalUsers: data?.users?.totalCount,
+ }),
}
);
const aggregates = [
{
title: app.dashboardPage.aggregates.totalFeedback.title,
- value: feedbackCount ?? 0,
+ value: dashboardAggregates?.totalFeedback ?? 0,
icon: HiOutlineChatBubbleLeftRight,
},
{
title: app.dashboardPage.aggregates.activeUsers.title,
- value: "42,069",
+ value: dashboardAggregates?.totalUsers ?? 0,
icon: HiOutlineUserGroup,
},
{
diff --git a/src/generated/graphql.ts b/src/generated/graphql.ts
index fd80a255a..d795eb5d4 100644
--- a/src/generated/graphql.ts
+++ b/src/generated/graphql.ts
@@ -3292,7 +3292,7 @@ export type DashboardAggregatesQueryVariables = Exact<{
}>;
-export type DashboardAggregatesQuery = { __typename?: 'Query', posts?: { __typename?: 'PostConnection', totalCount: number } | null };
+export type DashboardAggregatesQuery = { __typename?: 'Query', posts?: { __typename?: 'PostConnection', totalCount: number } | null, users?: { __typename?: 'UserConnection', totalCount: number } | null };
export type OrganizationQueryVariables = Exact<{
slug: Scalars['String']['input'];
@@ -3492,6 +3492,11 @@ export const DashboardAggregatesDocument = `
) {
totalCount
}
+ users(
+ filter: {userOrganizations: {some: {organization: {userOrganizations: {some: {userId: {equalTo: $userId}}}}}}}
+ ) {
+ totalCount
+ }
}
`;
diff --git a/src/lib/graphql/queries/dashboardAggregates.query.graphql b/src/lib/graphql/queries/dashboardAggregates.query.graphql
index 05277b430..e845bee85 100644
--- a/src/lib/graphql/queries/dashboardAggregates.query.graphql
+++ b/src/lib/graphql/queries/dashboardAggregates.query.graphql
@@ -10,4 +10,18 @@ query DashboardAggregates($userId: UUID!) {
) {
totalCount
}
+ # TODO: discuss a better approach. Aggregate data with the plugin is difficult across M2M relationships. This is a temporary solution.
+ users(
+ filter: {
+ userOrganizations: {
+ some: {
+ organization: {
+ userOrganizations: { some: { userId: { equalTo: $userId } } }
+ }
+ }
+ }
+ }
+ ) {
+ totalCount
+ }
}
From 8face19bbf9abd371bea2f12bcb2e90be658a39b Mon Sep 17 00:00:00 2001
From: hobbescodes <87732294+hobbescodes@users.noreply.github.com>
Date: Fri, 27 Dec 2024 22:58:48 -0600
Subject: [PATCH 04/72] refactor(organizations): update queries to user userId
variable
---
.../PinnedOrganizations/PinnedOrganizations.tsx | 15 ++++++++++++++-
.../OrganizationList/OrganizationList.tsx | 6 +++++-
src/generated/graphql.ts | 15 ++++++++-------
.../graphql/queries/organizations.query.graphql | 6 +++++-
4 files changed, 32 insertions(+), 10 deletions(-)
diff --git a/src/components/dashboard/PinnedOrganizations/PinnedOrganizations.tsx b/src/components/dashboard/PinnedOrganizations/PinnedOrganizations.tsx
index 6b18e9eb8..c3a10f8fe 100644
--- a/src/components/dashboard/PinnedOrganizations/PinnedOrganizations.tsx
+++ b/src/components/dashboard/PinnedOrganizations/PinnedOrganizations.tsx
@@ -9,6 +9,7 @@ import { OrganizationCard } from "components/dashboard";
import { ErrorBoundary } from "components/layout";
import { OrganizationOrderBy, useOrganizationsQuery } from "generated/graphql";
import { app } from "lib/config";
+import { useAuth } from "lib/hooks";
import type { Organization } from "generated/graphql";
@@ -17,6 +18,7 @@ import type { Organization } from "generated/graphql";
*/
const PinnedOrganizations = () => {
const router = useRouter();
+ const { user } = useAuth();
const {
data: pinnedOrganizations,
@@ -26,8 +28,10 @@ const PinnedOrganizations = () => {
{
first: 3,
orderBy: [OrganizationOrderBy.UserOrganizationsCountDesc],
+ userId: user?.id!,
},
{
+ enabled: !!user,
select: (data) => data?.organizations?.nodes,
}
);
@@ -76,7 +80,16 @@ const PinnedOrganizations = () => {
{isError ? (
) : (
-
+
{isLoading ? (
) : (
diff --git a/src/components/organization/OrganizationList/OrganizationList.tsx b/src/components/organization/OrganizationList/OrganizationList.tsx
index bcfd2506b..461b822f3 100644
--- a/src/components/organization/OrganizationList/OrganizationList.tsx
+++ b/src/components/organization/OrganizationList/OrganizationList.tsx
@@ -7,7 +7,7 @@ import { SkeletonArray } from "components/core";
import { ErrorBoundary } from "components/layout";
import { OrganizationListItem } from "components/organization";
import { OrganizationOrderBy, useOrganizationsQuery } from "generated/graphql";
-import { useDebounceValue, useSearchParams } from "lib/hooks";
+import { useAuth, useDebounceValue, useSearchParams } from "lib/hooks";
import type { StackProps } from "@omnidev/sigil";
import type { Organization } from "generated/graphql";
@@ -21,6 +21,8 @@ const OrganizationList = ({ ...props }: StackProps) => {
const [debouncedSearch] = useDebounceValue({ value: search });
+ const { user } = useAuth();
+
const {
data: organizations,
isLoading,
@@ -28,9 +30,11 @@ const OrganizationList = ({ ...props }: StackProps) => {
} = useOrganizationsQuery(
{
orderBy: [OrganizationOrderBy.UserOrganizationsCountDesc],
+ userId: user?.id!,
search: debouncedSearch,
},
{
+ enabled: !!user,
placeholderData: keepPreviousData,
select: (data) => data?.organizations?.nodes,
}
diff --git a/src/generated/graphql.ts b/src/generated/graphql.ts
index d795eb5d4..364bdc567 100644
--- a/src/generated/graphql.ts
+++ b/src/generated/graphql.ts
@@ -3304,6 +3304,7 @@ export type OrganizationQuery = { __typename?: 'Query', organizationBySlug?: { _
export type OrganizationsQueryVariables = Exact<{
first?: InputMaybe;
orderBy?: InputMaybe | OrganizationOrderBy>;
+ userId: Scalars['UUID']['input'];
search?: InputMaybe;
}>;
@@ -3589,11 +3590,11 @@ export const useInfiniteOrganizationQuery = <
useInfiniteOrganizationQuery.getKey = (variables: OrganizationQueryVariables) => ['Organization.infinite', variables];
export const OrganizationsDocument = `
- query Organizations($first: Int, $orderBy: [OrganizationOrderBy!], $search: String) {
+ query Organizations($first: Int, $orderBy: [OrganizationOrderBy!], $userId: UUID!, $search: String) {
organizations(
first: $first
orderBy: $orderBy
- filter: {name: {includesInsensitive: $search}}
+ filter: {name: {includesInsensitive: $search}, userOrganizations: {some: {userId: {equalTo: $userId}}}}
) {
nodes {
rowId
@@ -3613,19 +3614,19 @@ export const useOrganizationsQuery = <
TData = OrganizationsQuery,
TError = unknown
>(
- variables?: OrganizationsQueryVariables,
+ variables: OrganizationsQueryVariables,
options?: Omit, 'queryKey'> & { queryKey?: UseQueryOptions['queryKey'] }
) => {
return useQuery(
{
- queryKey: variables === undefined ? ['Organizations'] : ['Organizations', variables],
+ queryKey: ['Organizations', variables],
queryFn: useGraphqlClient(OrganizationsDocument).bind(null, variables),
...options
}
)};
-useOrganizationsQuery.getKey = (variables?: OrganizationsQueryVariables) => variables === undefined ? ['Organizations'] : ['Organizations', variables];
+useOrganizationsQuery.getKey = (variables: OrganizationsQueryVariables) => ['Organizations', variables];
export const useInfiniteOrganizationsQuery = <
TData = InfiniteData,
@@ -3639,14 +3640,14 @@ export const useInfiniteOrganizationsQuery = <
(() => {
const { queryKey: optionsQueryKey, ...restOptions } = options;
return {
- queryKey: optionsQueryKey ?? variables === undefined ? ['Organizations.infinite'] : ['Organizations.infinite', variables],
+ queryKey: optionsQueryKey ?? ['Organizations.infinite', variables],
queryFn: (metaData) => query({...variables, ...(metaData.pageParam ?? {})}),
...restOptions
}
})()
)};
-useInfiniteOrganizationsQuery.getKey = (variables?: OrganizationsQueryVariables) => variables === undefined ? ['Organizations.infinite'] : ['Organizations.infinite', variables];
+useInfiniteOrganizationsQuery.getKey = (variables: OrganizationsQueryVariables) => ['Organizations.infinite', variables];
export const PostsDocument = `
query Posts($projectId: UUID!) {
diff --git a/src/lib/graphql/queries/organizations.query.graphql b/src/lib/graphql/queries/organizations.query.graphql
index 4b1d2ce11..55a50835c 100644
--- a/src/lib/graphql/queries/organizations.query.graphql
+++ b/src/lib/graphql/queries/organizations.query.graphql
@@ -1,12 +1,16 @@
query Organizations(
$first: Int
$orderBy: [OrganizationOrderBy!]
+ $userId: UUID!
$search: String
) {
organizations(
first: $first
orderBy: $orderBy
- filter: { name: { includesInsensitive: $search } }
+ filter: {
+ name: { includesInsensitive: $search }
+ userOrganizations: { some: { userId: { equalTo: $userId } } }
+ }
) {
nodes {
rowId
From 6dc92d9cbed503475c32f2cb9a15c37f5e3985ca Mon Sep 17 00:00:00 2001
From: hobbescodes <87732294+hobbescodes@users.noreply.github.com>
Date: Sat, 28 Dec 2024 13:46:00 -0600
Subject: [PATCH 05/72] refactor(dashboard): remove average response time
aggregate
---
src/components/dashboard/DashboardPage/DashboardPage.tsx | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
diff --git a/src/components/dashboard/DashboardPage/DashboardPage.tsx b/src/components/dashboard/DashboardPage/DashboardPage.tsx
index c50a5b2ac..a6346f5c6 100644
--- a/src/components/dashboard/DashboardPage/DashboardPage.tsx
+++ b/src/components/dashboard/DashboardPage/DashboardPage.tsx
@@ -1,7 +1,6 @@
"use client";
import { Grid } from "@omnidev/sigil";
-import { GoClock } from "react-icons/go";
import {
HiOutlineChatBubbleLeftRight,
HiOutlineUserGroup,
@@ -45,11 +44,6 @@ const DashboardPage = () => {
value: dashboardAggregates?.totalUsers ?? 0,
icon: HiOutlineUserGroup,
},
- {
- title: app.dashboardPage.aggregates.avgResponseTime.title,
- value: "4.20h",
- icon: GoClock,
- },
];
return (
@@ -68,7 +62,7 @@ const DashboardPage = () => {
>
-
+
{aggregates.map(({ title, value, icon }) => (
Date: Sat, 28 Dec 2024 14:26:33 -0600
Subject: [PATCH 06/72] feature(dashboard): add query for recent feedback
---
.../RecentFeedback/RecentFeedback.tsx | 32 ++++++---
.../dashboard/Response/Response.tsx | 13 ++--
src/generated/graphql.ts | 65 +++++++++++++++++++
.../queries/recentFeedback.query.graphql | 22 +++++++
4 files changed, 118 insertions(+), 14 deletions(-)
create mode 100644 src/lib/graphql/queries/recentFeedback.query.graphql
diff --git a/src/components/dashboard/RecentFeedback/RecentFeedback.tsx b/src/components/dashboard/RecentFeedback/RecentFeedback.tsx
index 38e727230..880c545da 100644
--- a/src/components/dashboard/RecentFeedback/RecentFeedback.tsx
+++ b/src/components/dashboard/RecentFeedback/RecentFeedback.tsx
@@ -5,9 +5,10 @@ import { Flex } from "@omnidev/sigil";
import { SkeletonArray } from "components/core";
import { FeedbackCard, Response } from "components/dashboard";
import { ErrorBoundary } from "components/layout";
-import { useDataState } from "lib/hooks";
+import { useAuth } from "lib/hooks";
import type { ResponseType } from "components/dashboard";
+import { useRecentFeedbackQuery } from "generated/graphql";
interface Feedback {
id: string;
@@ -80,7 +81,21 @@ const FEEDBACK: Feedback[] = [
* Recent feedback section.
*/
const RecentFeedback = () => {
- const { isLoading, isError } = useDataState({ timeout: 500 });
+ const { user } = useAuth();
+
+ const {
+ data: recentFeedback,
+ isLoading,
+ isError,
+ } = useRecentFeedbackQuery(
+ {
+ userId: user?.id!,
+ },
+ {
+ enabled: !!user,
+ select: (data) => data?.posts?.nodes,
+ }
+ );
return (
{
{isLoading ? (
) : (
- FEEDBACK.map(({ id, sender, message, date, type }) => (
+ recentFeedback?.map((feedback) => (
))
)}
diff --git a/src/components/dashboard/Response/Response.tsx b/src/components/dashboard/Response/Response.tsx
index cbe35a83e..4df48afb8 100644
--- a/src/components/dashboard/Response/Response.tsx
+++ b/src/components/dashboard/Response/Response.tsx
@@ -1,6 +1,7 @@
"use client";
import { Badge, Flex, Text } from "@omnidev/sigil";
+import dayjs from "dayjs";
import { match } from "ts-pattern";
// NB: tried to use an enum here but had difficulties with runtime errors
@@ -9,13 +10,13 @@ export type ResponseType = "Neutral" | "Positive" | "Bug" | "Feature";
// NB: this prop drilling is under the assumption that the query from parent won't provide much overhead (i.e. parent is isolated query and has minimal nesting / a response is a direct child)
interface Props {
/** Feedback sender. */
- sender: string;
+ sender: string | undefined;
/** Feedback message. */
- message: string;
+ message: string | null | undefined;
/** Date feedback was published. */
- date: string;
+ date: Date | null | undefined;
/** Feedback type (i.e. category). */
- type: ResponseType;
+ type: ResponseType | undefined;
}
/**
@@ -27,7 +28,7 @@ const Response = ({ sender, message, date, type }: Props) => {
.with("Positive", () => "green")
.with("Bug", () => "red")
.with("Feature", () => "blue")
- .exhaustive();
+ .otherwise(() => "foreground.subtle");
return (
{
- {date}
+ {dayjs(date).fromNow()}
);
diff --git a/src/generated/graphql.ts b/src/generated/graphql.ts
index 364bdc567..854aca98b 100644
--- a/src/generated/graphql.ts
+++ b/src/generated/graphql.ts
@@ -3333,6 +3333,13 @@ export type ProjectsQueryVariables = Exact<{
export type ProjectsQuery = { __typename?: 'Query', projects?: { __typename?: 'ProjectConnection', nodes: Array<{ __typename?: 'Project', rowId: string, name?: string | null, description?: string | null, slug?: string | null } | null> } | null };
+export type RecentFeedbackQueryVariables = Exact<{
+ userId: Scalars['UUID']['input'];
+}>;
+
+
+export type RecentFeedbackQuery = { __typename?: 'Query', posts?: { __typename?: 'PostConnection', nodes: Array<{ __typename?: 'Post', rowId: string, createdAt?: Date | null, title?: string | null, description?: string | null, user?: { __typename?: 'User', rowId: string } | null } | null> } | null };
+
export type UserQueryVariables = Exact<{
walletAddress: Scalars['String']['input'];
}>;
@@ -3816,6 +3823,64 @@ export const useInfiniteProjectsQuery = <
useInfiniteProjectsQuery.getKey = (variables?: ProjectsQueryVariables) => variables === undefined ? ['Projects.infinite'] : ['Projects.infinite', variables];
+export const RecentFeedbackDocument = `
+ query RecentFeedback($userId: UUID!) {
+ posts(
+ first: 5
+ filter: {project: {organization: {userOrganizations: {some: {userId: {equalTo: $userId}}}}}}
+ ) {
+ nodes {
+ rowId
+ createdAt
+ title
+ description
+ user {
+ rowId
+ }
+ }
+ }
+}
+ `;
+
+export const useRecentFeedbackQuery = <
+ TData = RecentFeedbackQuery,
+ TError = unknown
+ >(
+ variables: RecentFeedbackQueryVariables,
+ options?: Omit, 'queryKey'> & { queryKey?: UseQueryOptions['queryKey'] }
+ ) => {
+
+ return useQuery(
+ {
+ queryKey: ['RecentFeedback', variables],
+ queryFn: useGraphqlClient(RecentFeedbackDocument).bind(null, variables),
+ ...options
+ }
+ )};
+
+useRecentFeedbackQuery.getKey = (variables: RecentFeedbackQueryVariables) => ['RecentFeedback', variables];
+
+export const useInfiniteRecentFeedbackQuery = <
+ TData = InfiniteData,
+ TError = unknown
+ >(
+ variables: RecentFeedbackQueryVariables,
+ options: Omit, 'queryKey'> & { queryKey?: UseInfiniteQueryOptions['queryKey'] }
+ ) => {
+ const query = useGraphqlClient(RecentFeedbackDocument)
+ return useInfiniteQuery(
+ (() => {
+ const { queryKey: optionsQueryKey, ...restOptions } = options;
+ return {
+ queryKey: optionsQueryKey ?? ['RecentFeedback.infinite', variables],
+ queryFn: (metaData) => query({...variables, ...(metaData.pageParam ?? {})}),
+ ...restOptions
+ }
+ })()
+ )};
+
+useInfiniteRecentFeedbackQuery.getKey = (variables: RecentFeedbackQueryVariables) => ['RecentFeedback.infinite', variables];
+
export const UserDocument = `
query User($walletAddress: String!) {
userByWalletAddress(walletAddress: $walletAddress) {
diff --git a/src/lib/graphql/queries/recentFeedback.query.graphql b/src/lib/graphql/queries/recentFeedback.query.graphql
new file mode 100644
index 000000000..e28aabaa3
--- /dev/null
+++ b/src/lib/graphql/queries/recentFeedback.query.graphql
@@ -0,0 +1,22 @@
+query RecentFeedback($userId: UUID!) {
+ posts(
+ first: 5
+ filter: {
+ project: {
+ organization: {
+ userOrganizations: { some: { userId: { equalTo: $userId } } }
+ }
+ }
+ }
+ ) {
+ nodes {
+ rowId
+ createdAt
+ title
+ description
+ user {
+ rowId
+ }
+ }
+ }
+}
From 75be978b1fbee8d0070bf93779967ad6ab1913cb Mon Sep 17 00:00:00 2001
From: hobbescodes <87732294+hobbescodes@users.noreply.github.com>
Date: Sat, 28 Dec 2024 14:33:51 -0600
Subject: [PATCH 07/72] chore(graphql): add comment regarding user first/last
in recent feedback query
---
src/lib/graphql/queries/recentFeedback.query.graphql | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/lib/graphql/queries/recentFeedback.query.graphql b/src/lib/graphql/queries/recentFeedback.query.graphql
index e28aabaa3..edaf58a52 100644
--- a/src/lib/graphql/queries/recentFeedback.query.graphql
+++ b/src/lib/graphql/queries/recentFeedback.query.graphql
@@ -16,6 +16,7 @@ query RecentFeedback($userId: UUID!) {
description
user {
rowId
+ # TODO: add `firstName` and `lastName` once the user is synced with the database
}
}
}
From dd2db616b68776076e1f3c7757cafc1ecd1273b0 Mon Sep 17 00:00:00 2001
From: hobbescodes <87732294+hobbescodes@users.noreply.github.com>
Date: Sat, 28 Dec 2024 15:09:33 -0600
Subject: [PATCH 08/72] feature(graphql): add query for weekly feedback
aggregates
---
src/generated/graphql.ts | 62 +++++++++++++++++++
.../queries/weeklyFeedback.query.graphql | 19 ++++++
2 files changed, 81 insertions(+)
create mode 100644 src/lib/graphql/queries/weeklyFeedback.query.graphql
diff --git a/src/generated/graphql.ts b/src/generated/graphql.ts
index 854aca98b..68ba2c1e1 100644
--- a/src/generated/graphql.ts
+++ b/src/generated/graphql.ts
@@ -3347,6 +3347,14 @@ export type UserQueryVariables = Exact<{
export type UserQuery = { __typename?: 'Query', userByWalletAddress?: { __typename?: 'User', createdAt?: Date | null, id: string, rowId: string, updatedAt?: Date | null, walletAddress?: string | null, userOrganizations: { __typename?: 'UserOrganizationConnection', nodes: Array<{ __typename?: 'UserOrganization', createdAt?: Date | null, organizationId: string, userId: string, organization?: { __typename?: 'Organization', id: string, createdAt?: Date | null, name?: string | null, rowId: string, slug?: string | null, updatedAt?: Date | null, projects: { __typename?: 'ProjectConnection', nodes: Array<{ __typename?: 'Project', slug?: string | null, rowId: string, organizationId: string, name?: string | null, image?: string | null, id: string, description?: string | null, createdAt?: Date | null } | null> } } | null } | null> } } | null };
+export type WeeklyFeedbackQueryVariables = Exact<{
+ userId: Scalars['UUID']['input'];
+ startDate: Scalars['Datetime']['input'];
+}>;
+
+
+export type WeeklyFeedbackQuery = { __typename?: 'Query', posts?: { __typename?: 'PostConnection', groupedAggregates?: Array<{ __typename?: 'PostAggregates', keys?: Array | null, distinctCount?: { __typename?: 'PostDistinctCountAggregates', rowId?: any | null } | null }> | null } | null };
+
export const ProjectFragmentDoc = `
fragment Project on Project {
@@ -3927,3 +3935,57 @@ export const useInfiniteUserQuery = <
)};
useInfiniteUserQuery.getKey = (variables: UserQueryVariables) => ['User.infinite', variables];
+
+export const WeeklyFeedbackDocument = `
+ query WeeklyFeedback($userId: UUID!, $startDate: Datetime!) {
+ posts(
+ filter: {project: {organization: {userOrganizations: {some: {userId: {equalTo: $userId}}}}}, createdAt: {greaterThanOrEqualTo: $startDate}}
+ ) {
+ groupedAggregates(groupBy: [CREATED_AT_TRUNCATED_TO_DAY]) {
+ keys
+ distinctCount {
+ rowId
+ }
+ }
+ }
+}
+ `;
+
+export const useWeeklyFeedbackQuery = <
+ TData = WeeklyFeedbackQuery,
+ TError = unknown
+ >(
+ variables: WeeklyFeedbackQueryVariables,
+ options?: Omit, 'queryKey'> & { queryKey?: UseQueryOptions['queryKey'] }
+ ) => {
+
+ return useQuery(
+ {
+ queryKey: ['WeeklyFeedback', variables],
+ queryFn: useGraphqlClient(WeeklyFeedbackDocument).bind(null, variables),
+ ...options
+ }
+ )};
+
+useWeeklyFeedbackQuery.getKey = (variables: WeeklyFeedbackQueryVariables) => ['WeeklyFeedback', variables];
+
+export const useInfiniteWeeklyFeedbackQuery = <
+ TData = InfiniteData,
+ TError = unknown
+ >(
+ variables: WeeklyFeedbackQueryVariables,
+ options: Omit, 'queryKey'> & { queryKey?: UseInfiniteQueryOptions['queryKey'] }
+ ) => {
+ const query = useGraphqlClient(WeeklyFeedbackDocument)
+ return useInfiniteQuery(
+ (() => {
+ const { queryKey: optionsQueryKey, ...restOptions } = options;
+ return {
+ queryKey: optionsQueryKey ?? ['WeeklyFeedback.infinite', variables],
+ queryFn: (metaData) => query({...variables, ...(metaData.pageParam ?? {})}),
+ ...restOptions
+ }
+ })()
+ )};
+
+useInfiniteWeeklyFeedbackQuery.getKey = (variables: WeeklyFeedbackQueryVariables) => ['WeeklyFeedback.infinite', variables];
diff --git a/src/lib/graphql/queries/weeklyFeedback.query.graphql b/src/lib/graphql/queries/weeklyFeedback.query.graphql
new file mode 100644
index 000000000..476ed6386
--- /dev/null
+++ b/src/lib/graphql/queries/weeklyFeedback.query.graphql
@@ -0,0 +1,19 @@
+query WeeklyFeedback($userId: UUID!, $startDate: Datetime!) {
+ posts(
+ filter: {
+ project: {
+ organization: {
+ userOrganizations: { some: { userId: { equalTo: $userId } } }
+ }
+ }
+ createdAt: { greaterThanOrEqualTo: $startDate }
+ }
+ ) {
+ groupedAggregates(groupBy: [CREATED_AT_TRUNCATED_TO_DAY]) {
+ keys
+ distinctCount {
+ rowId
+ }
+ }
+ }
+}
From f55bdc0e172e61d5229c5542ce6f7e8cdc483f73 Mon Sep 17 00:00:00 2001
From: hobbescodes <87732294+hobbescodes@users.noreply.github.com>
Date: Sat, 28 Dec 2024 16:29:29 -0600
Subject: [PATCH 09/72] feature(dashboard): apply query for generating feedback
overview chart
---
.../FeedbackOverview/FeedbackOverview.tsx | 52 ++++++++++++++-----
1 file changed, 40 insertions(+), 12 deletions(-)
diff --git a/src/components/dashboard/FeedbackOverview/FeedbackOverview.tsx b/src/components/dashboard/FeedbackOverview/FeedbackOverview.tsx
index 629daf5fc..ca376ea76 100644
--- a/src/components/dashboard/FeedbackOverview/FeedbackOverview.tsx
+++ b/src/components/dashboard/FeedbackOverview/FeedbackOverview.tsx
@@ -1,6 +1,7 @@
"use client";
import { Skeleton, useIsClient } from "@omnidev/sigil";
+import dayjs from "dayjs";
import {
Bar,
BarChart,
@@ -12,26 +13,53 @@ import {
import { FeedbackCard, FeedbackTooltip } from "components/dashboard";
import { ErrorBoundary } from "components/layout";
+import { useWeeklyFeedbackQuery } from "generated/graphql";
import { token } from "generated/panda/tokens";
-import { useDataState } from "lib/hooks";
-
-const getRandomInteger = () => Math.floor(Math.random() * 100);
+import { useAuth } from "lib/hooks";
/**
* Feedback overview section. Displays a bar chart that displays daily feedback volume for the past 7 days.
*/
const FeedbackOverview = () => {
- const isClient = useIsClient(),
- { isLoading, isError } = useDataState({ timeout: 600 });
+ const isClient = useIsClient();
+
+ const { user } = useAuth();
+
+ const oneWeekAgo = dayjs().subtract(1, "week").startOf("day").toDate();
+
+ const getFormattedDate = (diff: number) =>
+ dayjs(oneWeekAgo).add(diff, "day").format("ddd");
+
+ const {
+ data: weeklyFeedback,
+ isLoading,
+ isError,
+ } = useWeeklyFeedbackQuery(
+ {
+ userId: user?.id!,
+ startDate: oneWeekAgo,
+ },
+ {
+ enabled: !!user,
+ select: (data) =>
+ data?.posts?.groupedAggregates?.map((aggregate) => ({
+ name: dayjs(aggregate.keys?.[0]).format("ddd"),
+ total: Number(aggregate.distinctCount?.rowId),
+ })),
+ }
+ );
+
+ const getDailyTotal = (date: string) =>
+ weeklyFeedback?.find((item) => item.name === date)?.total ?? 0;
const DATA = [
- { name: "Mon", total: getRandomInteger() },
- { name: "Tue", total: getRandomInteger() },
- { name: "Wed", total: getRandomInteger() },
- { name: "Thu", total: getRandomInteger() },
- { name: "Fri", total: getRandomInteger() },
- { name: "Sat", total: getRandomInteger() },
- { name: "Sun", total: getRandomInteger() },
+ { name: getFormattedDate(0), total: getDailyTotal(getFormattedDate(0)) },
+ { name: getFormattedDate(1), total: getDailyTotal(getFormattedDate(1)) },
+ { name: getFormattedDate(2), total: getDailyTotal(getFormattedDate(2)) },
+ { name: getFormattedDate(3), total: getDailyTotal(getFormattedDate(3)) },
+ { name: getFormattedDate(4), total: getDailyTotal(getFormattedDate(4)) },
+ { name: getFormattedDate(5), total: getDailyTotal(getFormattedDate(5)) },
+ { name: getFormattedDate(6), total: getDailyTotal(getFormattedDate(6)) },
];
return (
From b741fe1a02ffbaed701b885bde719e9a3f2851f4 Mon Sep 17 00:00:00 2001
From: hobbescodes <87732294+hobbescodes@users.noreply.github.com>
Date: Sat, 28 Dec 2024 16:46:52 -0600
Subject: [PATCH 10/72] refactor(dashboard): remove date formatting functions
from react context
---
.../dashboard/FeedbackOverview/FeedbackOverview.tsx | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/components/dashboard/FeedbackOverview/FeedbackOverview.tsx b/src/components/dashboard/FeedbackOverview/FeedbackOverview.tsx
index ca376ea76..fb40c86b0 100644
--- a/src/components/dashboard/FeedbackOverview/FeedbackOverview.tsx
+++ b/src/components/dashboard/FeedbackOverview/FeedbackOverview.tsx
@@ -17,6 +17,11 @@ import { useWeeklyFeedbackQuery } from "generated/graphql";
import { token } from "generated/panda/tokens";
import { useAuth } from "lib/hooks";
+const oneWeekAgo = dayjs().subtract(1, "week").startOf("day").toDate();
+
+ const getFormattedDate = (diff: number) =>
+ dayjs(oneWeekAgo).add(diff, "day").format("ddd");
+
/**
* Feedback overview section. Displays a bar chart that displays daily feedback volume for the past 7 days.
*/
@@ -25,11 +30,6 @@ const FeedbackOverview = () => {
const { user } = useAuth();
- const oneWeekAgo = dayjs().subtract(1, "week").startOf("day").toDate();
-
- const getFormattedDate = (diff: number) =>
- dayjs(oneWeekAgo).add(diff, "day").format("ddd");
-
const {
data: weeklyFeedback,
isLoading,
From 4d53b3e69207d76db483aefa37a335d81a4a93af Mon Sep 17 00:00:00 2001
From: hobbescodes <87732294+hobbescodes@users.noreply.github.com>
Date: Sat, 28 Dec 2024 16:47:33 -0600
Subject: [PATCH 11/72] chore: format
---
.../dashboard/FeedbackOverview/FeedbackOverview.tsx | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/components/dashboard/FeedbackOverview/FeedbackOverview.tsx b/src/components/dashboard/FeedbackOverview/FeedbackOverview.tsx
index fb40c86b0..e3e774753 100644
--- a/src/components/dashboard/FeedbackOverview/FeedbackOverview.tsx
+++ b/src/components/dashboard/FeedbackOverview/FeedbackOverview.tsx
@@ -19,9 +19,9 @@ import { useAuth } from "lib/hooks";
const oneWeekAgo = dayjs().subtract(1, "week").startOf("day").toDate();
- const getFormattedDate = (diff: number) =>
- dayjs(oneWeekAgo).add(diff, "day").format("ddd");
-
+const getFormattedDate = (diff: number) =>
+ dayjs(oneWeekAgo).add(diff, "day").format("ddd");
+
/**
* Feedback overview section. Displays a bar chart that displays daily feedback volume for the past 7 days.
*/
From 1fac34e53220bcd71d6f3d72c8ac10a2b7558a49 Mon Sep 17 00:00:00 2001
From: hobbescodes <87732294+hobbescodes@users.noreply.github.com>
Date: Sat, 28 Dec 2024 16:50:21 -0600
Subject: [PATCH 12/72] refactor(dashboard): temporarily disabled new project
button
---
src/components/dashboard/DashboardPage/DashboardPage.tsx | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/components/dashboard/DashboardPage/DashboardPage.tsx b/src/components/dashboard/DashboardPage/DashboardPage.tsx
index a6346f5c6..24bcd0e16 100644
--- a/src/components/dashboard/DashboardPage/DashboardPage.tsx
+++ b/src/components/dashboard/DashboardPage/DashboardPage.tsx
@@ -56,6 +56,7 @@ const DashboardPage = () => {
label: app.dashboardPage.cta.newProject.label,
// TODO: get Sigil Icon component working and update accordingly. Context: https://github.com/omnidotdev/backfeed-app/pull/44#discussion_r1897974331
icon: ,
+ disabled: true,
},
],
}}
From 113f9aa214cf7ca1f349f0db6d093e9affade7f9 Mon Sep 17 00:00:00 2001
From: hobbescodes <87732294+hobbescodes@users.noreply.github.com>
Date: Sat, 28 Dec 2024 16:57:08 -0600
Subject: [PATCH 13/72] refactor(codegen): update scalars to map BigInt to
string
---
src/generated/graphql.ts | 6 +++---
src/lib/graphql/codegen.config.ts | 1 +
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/generated/graphql.ts b/src/generated/graphql.ts
index 68ba2c1e1..f7fc92f4b 100644
--- a/src/generated/graphql.ts
+++ b/src/generated/graphql.ts
@@ -15,7 +15,7 @@ export type Scalars = {
Boolean: { input: boolean; output: boolean; }
Int: { input: number; output: number; }
Float: { input: number; output: number; }
- BigInt: { input: any; output: any; }
+ BigInt: { input: string; output: string; }
Cursor: { input: string; output: string; }
Datetime: { input: Date; output: Date; }
UUID: { input: string; output: string; }
@@ -3316,7 +3316,7 @@ export type PostsQueryVariables = Exact<{
}>;
-export type PostsQuery = { __typename?: 'Query', posts?: { __typename?: 'PostConnection', nodes: Array<{ __typename?: 'Post', rowId: string, createdAt?: Date | null, title?: string | null, description?: string | null, user?: { __typename?: 'User', walletAddress?: string | null } | null, upvotes: { __typename?: 'UpvoteConnection', aggregates?: { __typename?: 'UpvoteAggregates', distinctCount?: { __typename?: 'UpvoteDistinctCountAggregates', rowId?: any | null } | null } | null, nodes: Array<{ __typename?: 'Upvote', rowId: string } | null> } } | null> } | null };
+export type PostsQuery = { __typename?: 'Query', posts?: { __typename?: 'PostConnection', nodes: Array<{ __typename?: 'Post', rowId: string, createdAt?: Date | null, title?: string | null, description?: string | null, user?: { __typename?: 'User', walletAddress?: string | null } | null, upvotes: { __typename?: 'UpvoteConnection', aggregates?: { __typename?: 'UpvoteAggregates', distinctCount?: { __typename?: 'UpvoteDistinctCountAggregates', rowId?: string | null } | null } | null, nodes: Array<{ __typename?: 'Upvote', rowId: string } | null> } } | null> } | null };
export type ProjectQueryVariables = Exact<{
organizationId: Scalars['UUID']['input'];
@@ -3353,7 +3353,7 @@ export type WeeklyFeedbackQueryVariables = Exact<{
}>;
-export type WeeklyFeedbackQuery = { __typename?: 'Query', posts?: { __typename?: 'PostConnection', groupedAggregates?: Array<{ __typename?: 'PostAggregates', keys?: Array | null, distinctCount?: { __typename?: 'PostDistinctCountAggregates', rowId?: any | null } | null }> | null } | null };
+export type WeeklyFeedbackQuery = { __typename?: 'Query', posts?: { __typename?: 'PostConnection', groupedAggregates?: Array<{ __typename?: 'PostAggregates', keys?: Array | null, distinctCount?: { __typename?: 'PostDistinctCountAggregates', rowId?: string | null } | null }> | null } | null };
export const ProjectFragmentDoc = `
diff --git a/src/lib/graphql/codegen.config.ts b/src/lib/graphql/codegen.config.ts
index 2421ba747..25b30fac2 100644
--- a/src/lib/graphql/codegen.config.ts
+++ b/src/lib/graphql/codegen.config.ts
@@ -39,6 +39,7 @@ const graphqlCodegenConfig: CodegenConfig = {
Datetime: "Date",
UUID: "string",
Cursor: "string",
+ BigInt: "string",
},
// https://the-guild.dev/graphql/codegen/plugins/typescript/typescript-react-query#using-graphql-request
// fetcher: "graphql-request",
From 0d18428fa51bd65bbb99eaa47b16a11857874464 Mon Sep 17 00:00:00 2001
From: hobbescodes <87732294+hobbescodes@users.noreply.github.com>
Date: Sat, 28 Dec 2024 18:53:20 -0600
Subject: [PATCH 14/72] refactor(dashboard): simplify logic for feedback chart
data
---
.../dashboard/FeedbackOverview/FeedbackOverview.tsx | 13 ++++---------
1 file changed, 4 insertions(+), 9 deletions(-)
diff --git a/src/components/dashboard/FeedbackOverview/FeedbackOverview.tsx b/src/components/dashboard/FeedbackOverview/FeedbackOverview.tsx
index e3e774753..1ed0d1d0f 100644
--- a/src/components/dashboard/FeedbackOverview/FeedbackOverview.tsx
+++ b/src/components/dashboard/FeedbackOverview/FeedbackOverview.tsx
@@ -52,15 +52,10 @@ const FeedbackOverview = () => {
const getDailyTotal = (date: string) =>
weeklyFeedback?.find((item) => item.name === date)?.total ?? 0;
- const DATA = [
- { name: getFormattedDate(0), total: getDailyTotal(getFormattedDate(0)) },
- { name: getFormattedDate(1), total: getDailyTotal(getFormattedDate(1)) },
- { name: getFormattedDate(2), total: getDailyTotal(getFormattedDate(2)) },
- { name: getFormattedDate(3), total: getDailyTotal(getFormattedDate(3)) },
- { name: getFormattedDate(4), total: getDailyTotal(getFormattedDate(4)) },
- { name: getFormattedDate(5), total: getDailyTotal(getFormattedDate(5)) },
- { name: getFormattedDate(6), total: getDailyTotal(getFormattedDate(6)) },
- ];
+ const DATA = Array.from({ length: 7 }).map((_, index) => ({
+ name: getFormattedDate(index),
+ total: getDailyTotal(getFormattedDate(index)),
+ }));
return (
Date: Sat, 28 Dec 2024 18:56:48 -0600
Subject: [PATCH 15/72] refactor(dashboard): dedup formatted date from data
array in feedback overview
---
.../dashboard/FeedbackOverview/FeedbackOverview.tsx | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/src/components/dashboard/FeedbackOverview/FeedbackOverview.tsx b/src/components/dashboard/FeedbackOverview/FeedbackOverview.tsx
index 1ed0d1d0f..4dfdda178 100644
--- a/src/components/dashboard/FeedbackOverview/FeedbackOverview.tsx
+++ b/src/components/dashboard/FeedbackOverview/FeedbackOverview.tsx
@@ -52,10 +52,14 @@ const FeedbackOverview = () => {
const getDailyTotal = (date: string) =>
weeklyFeedback?.find((item) => item.name === date)?.total ?? 0;
- const DATA = Array.from({ length: 7 }).map((_, index) => ({
- name: getFormattedDate(index),
- total: getDailyTotal(getFormattedDate(index)),
- }));
+ const DATA = Array.from({ length: 7 }).map((_, index) => {
+ const date = getFormattedDate(index);
+
+ return {
+ name: date,
+ total: getDailyTotal(date),
+ };
+ });
return (
Date: Sat, 28 Dec 2024 18:57:23 -0600
Subject: [PATCH 16/72] chore: remove newline
---
src/components/dashboard/FeedbackOverview/FeedbackOverview.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/dashboard/FeedbackOverview/FeedbackOverview.tsx b/src/components/dashboard/FeedbackOverview/FeedbackOverview.tsx
index 4dfdda178..92556e6b2 100644
--- a/src/components/dashboard/FeedbackOverview/FeedbackOverview.tsx
+++ b/src/components/dashboard/FeedbackOverview/FeedbackOverview.tsx
@@ -54,7 +54,7 @@ const FeedbackOverview = () => {
const DATA = Array.from({ length: 7 }).map((_, index) => {
const date = getFormattedDate(index);
-
+
return {
name: date,
total: getDailyTotal(date),
From 9c9bdf0b81ac4f6a1c8dd566137064eec0fdcf28 Mon Sep 17 00:00:00 2001
From: hobbescodes <87732294+hobbescodes@users.noreply.github.com>
Date: Sat, 28 Dec 2024 19:13:33 -0600
Subject: [PATCH 17/72] refactor(recent-feedback): update props for response
---
.../RecentFeedback/RecentFeedback.tsx | 75 +------------------
.../dashboard/Response/Response.tsx | 22 +++---
2 files changed, 13 insertions(+), 84 deletions(-)
diff --git a/src/components/dashboard/RecentFeedback/RecentFeedback.tsx b/src/components/dashboard/RecentFeedback/RecentFeedback.tsx
index 880c545da..99af90f30 100644
--- a/src/components/dashboard/RecentFeedback/RecentFeedback.tsx
+++ b/src/components/dashboard/RecentFeedback/RecentFeedback.tsx
@@ -5,77 +5,10 @@ import { Flex } from "@omnidev/sigil";
import { SkeletonArray } from "components/core";
import { FeedbackCard, Response } from "components/dashboard";
import { ErrorBoundary } from "components/layout";
-import { useAuth } from "lib/hooks";
-
-import type { ResponseType } from "components/dashboard";
import { useRecentFeedbackQuery } from "generated/graphql";
+import { useAuth } from "lib/hooks";
-interface Feedback {
- id: string;
- sender: string;
- message: string;
- date: string;
- type: ResponseType;
-}
-
-const FEEDBACK: Feedback[] = [
- {
- id: "1",
- sender: "Back Feed",
- message: "I still like turtles.",
- date: "30 seconds ago",
- type: "Neutral",
- },
- {
- id: "2",
- sender: "Feed Back",
- message: "The new dashboard layout is much more intuitive!",
- date: "4 minutes ago",
- type: "Positive",
- },
- {
- id: "3",
- sender: "Fed Front",
- message: "Having issues with the new export feature.",
- date: "3 hours ago",
- type: "Bug",
- },
- {
- id: "4",
- sender: "Back Fed",
- message: "Would love to be able to export feedback.",
- date: "2 days ago",
- type: "Feature",
- },
- {
- id: "5",
- sender: "Back Feed",
- message: "I am having troubles logging in.",
- date: "3 days ago",
- type: "Bug",
- },
- {
- id: "6",
- sender: "Back Fed",
- message: "I love turtles!",
- date: "4 days ago",
- type: "Positive",
- },
- {
- id: "7",
- sender: "Front Fed",
- message: "Would love to be able to export feedback.",
- date: "10 days ago",
- type: "Feature",
- },
- {
- id: "8",
- sender: "Back Feed",
- message: "I like turtles.",
- date: "69 days ago",
- type: "Neutral",
- },
-];
+import type { Post } from "generated/graphql";
/**
* Recent feedback section.
@@ -117,9 +50,7 @@ const RecentFeedback = () => {
recentFeedback?.map((feedback) => (
}
// TODO: make this dynamic once the data is streamed in
type="Neutral"
/>
diff --git a/src/components/dashboard/Response/Response.tsx b/src/components/dashboard/Response/Response.tsx
index 4df48afb8..5efc376d1 100644
--- a/src/components/dashboard/Response/Response.tsx
+++ b/src/components/dashboard/Response/Response.tsx
@@ -4,25 +4,23 @@ import { Badge, Flex, Text } from "@omnidev/sigil";
import dayjs from "dayjs";
import { match } from "ts-pattern";
+import type { Post } from "generated/graphql";
+
// NB: tried to use an enum here but had difficulties with runtime errors
export type ResponseType = "Neutral" | "Positive" | "Bug" | "Feature";
// NB: this prop drilling is under the assumption that the query from parent won't provide much overhead (i.e. parent is isolated query and has minimal nesting / a response is a direct child)
interface Props {
- /** Feedback sender. */
- sender: string | undefined;
- /** Feedback message. */
- message: string | null | undefined;
- /** Date feedback was published. */
- date: Date | null | undefined;
- /** Feedback type (i.e. category). */
- type: ResponseType | undefined;
+ /** Feedback details. */
+ feedback: Partial;
+ /** Feedback type */
+ type: ResponseType;
}
/**
* Recent feedback response.
*/
-const Response = ({ sender, message, date, type }: Props) => {
+const Response = ({ feedback, type }: Props) => {
const color = match(type)
.with("Neutral", () => "foreground.subtle")
.with("Positive", () => "green")
@@ -41,7 +39,7 @@ const Response = ({ sender, message, date, type }: Props) => {
- {sender}
+ {feedback?.rowId}
@@ -50,12 +48,12 @@ const Response = ({ sender, message, date, type }: Props) => {
- {message}
+ {feedback?.description}
- {dayjs(date).fromNow()}
+ {dayjs(feedback?.createdAt).fromNow()}
);
From 0ca4c5988c82555ed27ec3017de5568444014faa Mon Sep 17 00:00:00 2001
From: hobbescodes <87732294+hobbescodes@users.noreply.github.com>
Date: Sat, 28 Dec 2024 19:15:58 -0600
Subject: [PATCH 18/72] chore: update comments
---
src/components/dashboard/RecentFeedback/RecentFeedback.tsx | 1 -
src/components/dashboard/Response/Response.tsx | 1 +
2 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/dashboard/RecentFeedback/RecentFeedback.tsx b/src/components/dashboard/RecentFeedback/RecentFeedback.tsx
index 99af90f30..4e5980eef 100644
--- a/src/components/dashboard/RecentFeedback/RecentFeedback.tsx
+++ b/src/components/dashboard/RecentFeedback/RecentFeedback.tsx
@@ -51,7 +51,6 @@ const RecentFeedback = () => {
}
- // TODO: make this dynamic once the data is streamed in
type="Neutral"
/>
))
diff --git a/src/components/dashboard/Response/Response.tsx b/src/components/dashboard/Response/Response.tsx
index 5efc376d1..a23cd8fa1 100644
--- a/src/components/dashboard/Response/Response.tsx
+++ b/src/components/dashboard/Response/Response.tsx
@@ -14,6 +14,7 @@ interface Props {
/** Feedback details. */
feedback: Partial;
/** Feedback type */
+ // TODO: remove and capture from `feedback` prop once discussed / db schema is updated
type: ResponseType;
}
From 6d6c97685bc827e55b92668ced4bfd92f1d72d59 Mon Sep 17 00:00:00 2001
From: hobbescodes <87732294+hobbescodes@users.noreply.github.com>
Date: Sat, 28 Dec 2024 22:15:22 -0600
Subject: [PATCH 19/72] docs: update response jsdoc
Co-authored-by: Brian Cooper <20056195+coopbri@users.noreply.github.com>
---
src/components/dashboard/Response/Response.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/dashboard/Response/Response.tsx b/src/components/dashboard/Response/Response.tsx
index a23cd8fa1..65c2fd23b 100644
--- a/src/components/dashboard/Response/Response.tsx
+++ b/src/components/dashboard/Response/Response.tsx
@@ -13,7 +13,7 @@ export type ResponseType = "Neutral" | "Positive" | "Bug" | "Feature";
interface Props {
/** Feedback details. */
feedback: Partial;
- /** Feedback type */
+ /** Feedback type. */
// TODO: remove and capture from `feedback` prop once discussed / db schema is updated
type: ResponseType;
}
From fc15b13ca919c26ed568e581c390618422159aed Mon Sep 17 00:00:00 2001
From: hobbescodes <87732294+hobbescodes@users.noreply.github.com>
Date: Sat, 28 Dec 2024 22:30:27 -0600
Subject: [PATCH 20/72] refactor(feedback-overview): set yaxis to always scale
on natural numbers
---
.../dashboard/FeedbackOverview/FeedbackOverview.tsx | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/components/dashboard/FeedbackOverview/FeedbackOverview.tsx b/src/components/dashboard/FeedbackOverview/FeedbackOverview.tsx
index 92556e6b2..f0d4c4191 100644
--- a/src/components/dashboard/FeedbackOverview/FeedbackOverview.tsx
+++ b/src/components/dashboard/FeedbackOverview/FeedbackOverview.tsx
@@ -79,7 +79,12 @@ const FeedbackOverview = () => {
{/* NB: the explicit width removes some unecessary spacing on the y-axis. This should be fine for 3-digit numbers, but may need to be adjusted for larger numbers. */}
-
+
Date: Sun, 29 Dec 2024 10:37:27 -0600
Subject: [PATCH 21/72] refactor(graphql): update organization query
---
src/generated/graphql.ts | 21 ++++++++++++++-----
.../queries/organization.query.graphql | 17 ++++++++++++---
2 files changed, 30 insertions(+), 8 deletions(-)
diff --git a/src/generated/graphql.ts b/src/generated/graphql.ts
index f7fc92f4b..38ecfe5da 100644
--- a/src/generated/graphql.ts
+++ b/src/generated/graphql.ts
@@ -3295,11 +3295,11 @@ export type DashboardAggregatesQueryVariables = Exact<{
export type DashboardAggregatesQuery = { __typename?: 'Query', posts?: { __typename?: 'PostConnection', totalCount: number } | null, users?: { __typename?: 'UserConnection', totalCount: number } | null };
export type OrganizationQueryVariables = Exact<{
- slug: Scalars['String']['input'];
+ rowId: Scalars['UUID']['input'];
}>;
-export type OrganizationQuery = { __typename?: 'Query', organizationBySlug?: { __typename?: 'Organization', rowId: string, name?: string | null, slug?: string | null } | null };
+export type OrganizationQuery = { __typename?: 'Query', organization?: { __typename?: 'Organization', rowId: string, name?: string | null, userOrganizations: { __typename?: 'UserOrganizationConnection', totalCount: number }, projects: { __typename?: 'ProjectConnection', nodes: Array<{ __typename?: 'Project', name?: string | null, description?: string | null, posts: { __typename?: 'PostConnection', totalCount: number } } | null> } } | null };
export type OrganizationsQueryVariables = Exact<{
first?: InputMaybe;
@@ -3556,11 +3556,22 @@ export const useInfiniteDashboardAggregatesQuery = <
useInfiniteDashboardAggregatesQuery.getKey = (variables: DashboardAggregatesQueryVariables) => ['DashboardAggregates.infinite', variables];
export const OrganizationDocument = `
- query Organization($slug: String!) {
- organizationBySlug(slug: $slug) {
+ query Organization($rowId: UUID!) {
+ organization(rowId: $rowId) {
rowId
name
- slug
+ userOrganizations {
+ totalCount
+ }
+ projects {
+ nodes {
+ name
+ description
+ posts {
+ totalCount
+ }
+ }
+ }
}
}
`;
diff --git a/src/lib/graphql/queries/organization.query.graphql b/src/lib/graphql/queries/organization.query.graphql
index 8cffe3200..0b944d089 100644
--- a/src/lib/graphql/queries/organization.query.graphql
+++ b/src/lib/graphql/queries/organization.query.graphql
@@ -1,7 +1,18 @@
-query Organization($slug: String!) {
- organizationBySlug(slug: $slug) {
+query Organization($rowId: UUID!) {
+ organization(rowId: $rowId) {
rowId
name
- slug
+ userOrganizations {
+ totalCount
+ }
+ projects {
+ nodes {
+ name
+ description
+ posts {
+ totalCount
+ }
+ }
+ }
}
}
From 5cb27bdb4973b444b54a2e8a664f41c766c82e1d Mon Sep 17 00:00:00 2001
From: hobbescodes <87732294+hobbescodes@users.noreply.github.com>
Date: Sun, 29 Dec 2024 10:54:16 -0600
Subject: [PATCH 22/72] refactor(organization): cherry-pick partial support for
RSC
---
.../organizations/[organizationId]/page.tsx | 53 ++++++-------------
src/components/organization/index.ts | 1 +
2 files changed, 17 insertions(+), 37 deletions(-)
diff --git a/src/app/organizations/[organizationId]/page.tsx b/src/app/organizations/[organizationId]/page.tsx
index fe95e69bc..41671fe7a 100644
--- a/src/app/organizations/[organizationId]/page.tsx
+++ b/src/app/organizations/[organizationId]/page.tsx
@@ -1,40 +1,32 @@
-"use client";
-
-import { Grid } from "@omnidev/sigil";
-import { notFound, useParams, useRouter } from "next/navigation";
+import { notFound } from "next/navigation";
import { HiOutlineFolder } from "react-icons/hi2";
import { LuPlusCircle } from "react-icons/lu";
import { Page } from "components/layout";
-import {
- OrganizationActions,
- OrganizationMetrics,
- OrganizationProjectsOverview,
-} from "components/organization";
+import { OrganizationOverview } from "components/organization";
import { app } from "lib/config";
-import { useAuth, useDataState } from "lib/hooks";
+import { getAuthSession } from "lib/util";
+
+interface Props {
+ /** Organization page params. */
+ params: Promise<{ organizationId: string }>;
+}
/**
* Organization overview page.
*/
-const OrganizationPage = () => {
- const { isAuthenticated } = useAuth();
-
- const params = useParams<{ organizationId: string }>(),
- router = useRouter();
-
- const { isLoading, isError } = useDataState();
-
- const navigateToProjectsPage = () =>
- router.push(`/organizations/${params.organizationId}/projects`);
+const OrganizationPage = async ({ params }: Props) => {
+ const { organizationId } = await params;
+
+ const session = await getAuthSession();
// TODO: when data is streamed in, this condition should be updated to check for the existence of the organization
- if (!isAuthenticated) notFound();
+ if (!session) notFound();
return (
{
// TODO: get Sigil Icon component working and update accordingly. Context: https://github.com/omnidotdev/backfeed-app/pull/44#discussion_r1897974331
icon: ,
variant: "outline",
- onClick: navigateToProjectsPage,
+ // TODO: add href upon merge of https://github.com/omnidotdev/backfeed-app/pull/39
},
{
label: app.organizationPage.header.cta.newProject.label,
@@ -52,20 +44,7 @@ const OrganizationPage = () => {
],
}}
>
-
-
-
- {/* NB: these aggregates should be fine to fetch from the top level `organizationQuery` */}
-
-
-
-
+
);
};
diff --git a/src/components/organization/index.ts b/src/components/organization/index.ts
index f5b9a89fd..9ac659bce 100644
--- a/src/components/organization/index.ts
+++ b/src/components/organization/index.ts
@@ -3,5 +3,6 @@ export { default as OrganizationFilters } from "./OrganizationFilters/Organizati
export { default as OrganizationList } from "./OrganizationList/OrganizationList";
export { default as OrganizationListItem } from "./OrganizationListItem/OrganizationListItem";
export { default as OrganizationMetrics } from "./OrganizationMetrics/OrganizationMetrics";
+export { default as OrganizationOverview } from "./OrganizationOverview/OrganizationOverview";
export { default as OrganizationProjectsOverview } from "./OrganizationProjectsOverview/OrganizationProjectsOverview";
export { default as ProjectCard } from "./ProjectCard/ProjectCard";
From 1fe3ac0b7158d22814a460acc4d48276b1700412 Mon Sep 17 00:00:00 2001
From: hobbescodes <87732294+hobbescodes@users.noreply.github.com>
Date: Sun, 29 Dec 2024 10:55:09 -0600
Subject: [PATCH 23/72] refactor(organization): cherry-pick partial support for
RSC
---
.../organizations/[organizationId]/page.tsx | 2 +-
.../OrganizationOverview.tsx | 34 +++++++++++++++++++
2 files changed, 35 insertions(+), 1 deletion(-)
create mode 100644 src/components/organization/OrganizationOverview/OrganizationOverview.tsx
diff --git a/src/app/organizations/[organizationId]/page.tsx b/src/app/organizations/[organizationId]/page.tsx
index 41671fe7a..0ce9facd2 100644
--- a/src/app/organizations/[organizationId]/page.tsx
+++ b/src/app/organizations/[organizationId]/page.tsx
@@ -17,7 +17,7 @@ interface Props {
*/
const OrganizationPage = async ({ params }: Props) => {
const { organizationId } = await params;
-
+
const session = await getAuthSession();
// TODO: when data is streamed in, this condition should be updated to check for the existence of the organization
diff --git a/src/components/organization/OrganizationOverview/OrganizationOverview.tsx b/src/components/organization/OrganizationOverview/OrganizationOverview.tsx
new file mode 100644
index 000000000..d0fc823ed
--- /dev/null
+++ b/src/components/organization/OrganizationOverview/OrganizationOverview.tsx
@@ -0,0 +1,34 @@
+"use client";
+
+import { Grid } from "@omnidev/sigil";
+import {
+ OrganizationActions,
+ OrganizationMetrics,
+ OrganizationProjectsOverview,
+} from "components/organization";
+import { useDataState } from "lib/hooks";
+
+const OrganizationOverview = () => {
+ const { isLoading, isError } = useDataState();
+
+ return (
+ <>
+
+
+
+ {/* NB: these aggregates should be fine to fetch from the top level `organizationQuery` */}
+
+
+
+
+ >
+ );
+};
+
+export default OrganizationOverview;
From aaf75f8ff3fb518965ef01bb6339934ba94a20c6 Mon Sep 17 00:00:00 2001
From: hobbescodes <87732294+hobbescodes@users.noreply.github.com>
Date: Sun, 29 Dec 2024 11:28:08 -0600
Subject: [PATCH 24/72] feature(organization): appropriately fetch information
for projects
---
.../organizations/[organizationId]/page.tsx | 19 ++++--
.../OrganizationOverview.tsx | 9 ++-
.../OrganizationProjectsOverview.tsx | 60 ++++++-------------
.../organization/ProjectCard/ProjectCard.tsx | 24 ++++----
src/generated/graphql.ts | 6 +-
.../queries/organization.query.graphql | 4 +-
6 files changed, 53 insertions(+), 69 deletions(-)
diff --git a/src/app/organizations/[organizationId]/page.tsx b/src/app/organizations/[organizationId]/page.tsx
index 0ce9facd2..987e31723 100644
--- a/src/app/organizations/[organizationId]/page.tsx
+++ b/src/app/organizations/[organizationId]/page.tsx
@@ -1,12 +1,16 @@
+import request from "graphql-request";
import { notFound } from "next/navigation";
import { HiOutlineFolder } from "react-icons/hi2";
import { LuPlusCircle } from "react-icons/lu";
import { Page } from "components/layout";
import { OrganizationOverview } from "components/organization";
-import { app } from "lib/config";
+import { OrganizationDocument } from "generated/graphql";
+import { API_BASE_URL, app } from "lib/config";
import { getAuthSession } from "lib/util";
+import type { OrganizationQuery, OrganizationQueryVariables } from "generated/graphql";
+
interface Props {
/** Organization page params. */
params: Promise<{ organizationId: string }>;
@@ -20,13 +24,18 @@ const OrganizationPage = async ({ params }: Props) => {
const session = await getAuthSession();
- // TODO: when data is streamed in, this condition should be updated to check for the existence of the organization
- if (!session) notFound();
+ const { organization }: OrganizationQuery = await request({
+ url: API_BASE_URL!,
+ document: OrganizationDocument,
+ variables: { rowId: organizationId } as OrganizationQueryVariables,
+ })
+
+ if (!session || !organization) notFound();
return (
{
],
}}
>
-
+
);
};
diff --git a/src/components/organization/OrganizationOverview/OrganizationOverview.tsx b/src/components/organization/OrganizationOverview/OrganizationOverview.tsx
index d0fc823ed..0a19f4fcf 100644
--- a/src/components/organization/OrganizationOverview/OrganizationOverview.tsx
+++ b/src/components/organization/OrganizationOverview/OrganizationOverview.tsx
@@ -8,12 +8,17 @@ import {
} from "components/organization";
import { useDataState } from "lib/hooks";
-const OrganizationOverview = () => {
+interface Props {
+ /** Organization ID. */
+ organizationId: string;
+}
+
+const OrganizationOverview = ({ organizationId }: Props) => {
const { isLoading, isError } = useDataState();
return (
<>
-
+
{/* NB: these aggregates should be fine to fetch from the top level `organizationQuery` */}
diff --git a/src/components/organization/OrganizationProjectsOverview/OrganizationProjectsOverview.tsx b/src/components/organization/OrganizationProjectsOverview/OrganizationProjectsOverview.tsx
index 6d544e530..f5d874b56 100644
--- a/src/components/organization/OrganizationProjectsOverview/OrganizationProjectsOverview.tsx
+++ b/src/components/organization/OrganizationProjectsOverview/OrganizationProjectsOverview.tsx
@@ -7,7 +7,9 @@ import { SkeletonArray } from "components/core";
import { ErrorBoundary, SectionContainer } from "components/layout";
import { ProjectCard } from "components/organization";
import { app } from "lib/config";
-import { useDataState } from "lib/hooks";
+import { useOrganizationQuery } from "generated/graphql";
+
+import type { Project } from "generated/graphql";
interface OrganizationProject {
/** Organization ID. */
@@ -18,47 +20,21 @@ interface OrganizationProject {
description: string;
}
-const PROJECTS: OrganizationProject[] = [
- {
- id: "1",
- name: "Mobile App Feedback",
- description:
- "We are actively gathering detailed user feedback for our iOS and Android applications to enhance user experience and functionality. This includes identifying key pain points, usability issues, and feature requests from our diverse user base. Our primary focus is on improving app performance, refining navigation flows, and introducing user-driven features that align with customer needs. Additionally, we are seeking feedback on visual design updates and accessibility improvements to ensure the app meets the highest standards for all users. This project is crucial for maintaining our competitive edge in the mobile app market and fostering customer loyalty.",
- },
- {
- id: "2",
- name: "Web Platform Beta",
- description: "Beta testing feedback for the new web platform",
- },
- {
- id: "3",
- name: "Desktop Client",
- description: "User experience feedback for desktop applications",
- },
- {
- id: "4",
- name: "E-commerce Platform Upgrade",
- description:
- "Feedback for the upgraded e-commerce platform features and user flow.",
- },
- {
- id: "5",
- name: "AI Chatbot Testing",
- description: "Testing and collecting responses for our AI chatbot.",
- },
- {
- id: "6",
- name: "Enterprise CRM Feedback",
- description: "Gathering feedback on our enterprise CRM system.",
- },
-];
+interface Props {
+ /** Organization ID. */
+ organizationId: string
+}
/**
* Organization projects overview.
*/
-const OrganizationProjectsOverview = () => {
- const { isLoading, isError } = useDataState();
-
+const OrganizationProjectsOverview = ({ organizationId }: Props) => {
+ const { data: projects, isLoading, isError } = useOrganizationQuery({
+ rowId: organizationId,
+ }, {
+ select: (data) => data?.organization?.projects?.nodes
+ })
+
return (
{
{isLoading ? (
) : (
- PROJECTS.map(({ id, name, description }) => (
+ projects?.map((project) => (
}
// !!NB: explicitly set the height of the card to prevent CLS issues with loading and error states.
h={48}
/>
diff --git a/src/components/organization/ProjectCard/ProjectCard.tsx b/src/components/organization/ProjectCard/ProjectCard.tsx
index a7d75689a..bbb88e08a 100644
--- a/src/components/organization/ProjectCard/ProjectCard.tsx
+++ b/src/components/organization/ProjectCard/ProjectCard.tsx
@@ -21,13 +21,14 @@ import { OverflowText } from "components/core";
import { useDataState } from "lib/hooks";
import type { FlexProps } from "@omnidev/sigil";
+import type { Project } from "generated/graphql";
import type { IconType } from "react-icons";
interface ProjectMetric {
/** Visual icon. */
icon: IconType;
/** Metric value. */
- value: string | number;
+ value: number | undefined;
/** Metric type. */
type: "Responses" | "Users" | "Updated";
/** Container props for `type` and `value`. Used to override default styles. */
@@ -35,18 +36,14 @@ interface ProjectMetric {
}
interface Props extends FlexProps {
- /** Project ID. */
- id: string;
- /** Name of the organization. */
- name: string;
- /** Description of the organization. */
- description: string;
+ /** Project details. */
+ project: Partial;
}
/**
* Project, nested within an organization. A project outlines an application or other kind of product or service that aggregates and contains scoped feedback.
*/
-const ProjectCard = ({ id, name, description, ...rest }: Props) => {
+const ProjectCard = ({ project, ...rest }: Props) => {
// !NB: this is to represent where we would want to fetch the aggregate data (total feedback and active users). This will keep the top level `projectsQuery` clean.
const { isLoading, isError } = useDataState({ timeout: 800 });
@@ -55,11 +52,12 @@ const ProjectCard = ({ id, name, description, ...rest }: Props) => {
const PROJECT_METRICS: ProjectMetric[] = [
{
icon: HiOutlineChatBubbleLeftRight,
- value: 420,
+ value: project?.posts?.totalCount,
type: "Responses",
},
{
icon: HiOutlineUserGroup,
+ // TODO: determine the best way to get the totally number of users for a project
value: 69,
type: "Users",
},
@@ -75,7 +73,9 @@ const ProjectCard = ({ id, name, description, ...rest }: Props) => {
p={8}
{...rest}
>
-
+