Skip to content

Commit

Permalink
feat(Dashboard): rewrite query for kysely usage
Browse files Browse the repository at this point in the history
  • Loading branch information
LamaEats committed Jun 20, 2024
1 parent 5c6effa commit 0d673a5
Show file tree
Hide file tree
Showing 20 changed files with 837 additions and 150 deletions.
21 changes: 8 additions & 13 deletions src/components/DashboardPage/DashboardPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ import { FiltersPanel } from '../FiltersPanel/FiltersPanel';

import { tr } from './DashboardPage.i18n';

export const projectsLimit = 3;

export const DashboardPage = ({ user, ssrTime, defaultPresetFallback }: ExternalPageProps) => {
const utils = trpc.useContext();

Expand All @@ -35,29 +33,26 @@ export const DashboardPage = ({ user, ssrTime, defaultPresetFallback }: External
});

const { data, isLoading, isFetching, fetchNextPage, hasNextPage } =
trpc.project.getUserProjectsWithGoals.useInfiniteQuery(
{
limit: projectsLimit,
goalsQuery: queryState,
},
trpc.v2.project.userProjectsWithGoals.useInfiniteQuery(
{ goalsQuery: queryState },
{
getNextPageParam: (p) => p.nextCursor,
getNextPageParam: (p) => p.pagiantion.offset,
keepPreviousData: true,
staleTime: refreshInterval,
},
);

const pages = useMemo(() => data?.pages || [], [data?.pages]);

const [groupsOnScreen, goals, totalGoalsCount] = useMemo(() => {
const [groupsOnScreen, goalsCount, totalGoalsCount] = useMemo(() => {
const groups = pages?.[0]?.groups;

const gr = pages.reduce<typeof groups>((acc, cur) => {
acc.push(...cur.groups);
return acc;
}, []);

return [gr, gr.flatMap((group) => group.goals), pages?.[0]?.totalGoalsCount];
return [gr, gr.flatMap((group) => group.goals).length, pages?.[pages.length - 1].totalGoalsCount ?? 0];
}, [pages]);

useFMPMetric(!!data);
Expand Down Expand Up @@ -99,14 +94,14 @@ export const DashboardPage = ({ user, ssrTime, defaultPresetFallback }: External
currentPresetTitle: currentPreset?.title,
})}
total={totalGoalsCount}
counter={goals?.length}
counter={goalsCount}
filterPreset={preset}
loading={isLoading}
/>
}
>
<ListView onKeyboardClick={handleItemEnter}>
{groupsOnScreen?.map(({ project, goals }) => (
{groupsOnScreen?.map(({ goals, ...project }) => (
<ProjectListItemCollapsable
key={project.id}
interactive={false}
Expand All @@ -119,7 +114,7 @@ export const DashboardPage = ({ user, ssrTime, defaultPresetFallback }: External
</TreeViewElement>
))}
>
{nullable(!goals.length, () => (
{nullable(!goals?.length, () => (
<InlineCreateGoalControl project={project} />
))}
</ProjectListItemCollapsable>
Expand Down
2 changes: 1 addition & 1 deletion src/components/ExploreProjectsPage/ExploreProjectsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const ExploreProjectsPage = ({ user, ssrTime }: ExternalPageProps) => {
<TableRowItem title={<TableRowItemTitle size="l">{p.title}</TableRowItemTitle>}>
<ProjectListItem
id={p.id}
stargizers={p.stargizers}
stargizers={p._count.stargizers}
owner={p.activity}
starred={p._isStarred}
watching={p._isWatching}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const ExploreProjectsPage = ({ user, ssrTime }: ExternalPageProps) => {
<TableRowItem title={<TableRowItemTitle size="l">{p.title}</TableRowItemTitle>}>
<ProjectListItem
id={p.id}
stargizers={p.stargizers}
stargizers={p._count.stargizers}
owner={p.activity}
starred={p._isStarred}
watching={p._isWatching}
Expand Down
4 changes: 2 additions & 2 deletions src/components/ProjectListItem/ProjectListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import s from './ProjectListItem.module.css';

interface ProjectListItemProps {
id: string;
stargizers: Pick<ActivityByIdReturnType, 'id'>[];
stargizers: number;
editable?: boolean;
owner?: ActivityByIdReturnType;
participants?: ActivityByIdReturnType[];
Expand Down Expand Up @@ -68,7 +68,7 @@ export const ProjectListItem: React.FC<ProjectListItemProps & ComponentProps<typ
id={id}
starred={starred}
watching={watching}
stargizersCounter={stargizers.length}
stargizersCounter={stargizers}
/>
),
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ export const ProjectListItemCollapsable: React.FC<ProjectListItemCollapsableProp
<TableRowItemTitle size={titleSize} {...projectListItemTitle.attr}>
{project.title}
</TableRowItemTitle>
{nullable(project.children.length, (length) => (
{nullable(project._count.children, (count) => (
<div className={s.ProjectIcons}>
<IconServersOutline size="xs" />
<Text size="xs">{length}</Text>
<Text size="xs">{count}</Text>
</div>
))}
</div>
Expand All @@ -52,7 +52,7 @@ export const ProjectListItemCollapsable: React.FC<ProjectListItemCollapsableProp
>
<ProjectListItem
id={project.id}
stargizers={project.stargizers}
stargizers={project._count.stargizers}
owner={project.activity}
participants={project.participants}
starred={project._isStarred}
Expand Down
5 changes: 2 additions & 3 deletions src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DashboardPage, projectsLimit } from '../components/DashboardPage/DashboardPage';
import { DashboardPage } from '../components/DashboardPage/DashboardPage';
import { declareSsrProps } from '../utils/declareSsrProps';
import { filtersPanelSsrInit } from '../utils/filters';

Expand All @@ -8,9 +8,8 @@ export const getServerSideProps = declareSsrProps(

const { ssrHelpers } = params;

await ssrHelpers.project.getUserProjectsWithGoals.fetchInfinite({
await ssrHelpers.v2.project.userProjectsWithGoals.fetchInfinite({
goalsQuery: queryState,
limit: projectsLimit,
});

return {
Expand Down
26 changes: 14 additions & 12 deletions src/utils/dateTime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ interface LocaleArg {
locale: TLocale;
}

export const createLocaleDate = (date: Date, { locale }: LocaleArg): string =>
export const createLocaleDate = (date: Date | string, { locale }: LocaleArg): string =>
new Intl.DateTimeFormat(locale, {
day: '2-digit',
month: '2-digit',
year: 'numeric',
}).format(date);
}).format(new Date(date));

export const currentLocaleDate = ({ locale }: LocaleArg): string => createLocaleDate(new Date(), { locale });

Expand Down Expand Up @@ -45,10 +45,10 @@ export const parseLocaleDate = (date: string | Date, { locale }: LocaleArg): Dat
return parsers[resolvedLocale](date);
};

export const getYearFromDate = (date: Date): number => date.getFullYear();
export const getYearFromDate = (date: Date | string): number => new Date(date).getFullYear();

export const getQuarterFromDate = (date: Date): QuartersKeys =>
`Q${Math.floor(date.getMonth() / 3 + 1)}` as QuartersKeys;
export const getQuarterFromDate = (date: Date | string): QuartersKeys =>
`Q${Math.floor(new Date(date).getMonth() / 3 + 1)}` as QuartersKeys;

export const getAvailableYears = (n = 5, currY = new Date().getFullYear()): number[] =>
Array(n)
Expand Down Expand Up @@ -189,18 +189,19 @@ export const dateAgo = (date: Date, pastDate: number, { locale }: LocaleArg): st
}
};

export const isPastDate = (date: Date): boolean => new Date(date) < new Date();
export const isPastDate = (date: Date | string): boolean => new Date(date) < new Date();

// Return string in format yyyy-mm-dd from Estimate value (in UTC timezone)

export const getDateStringFromEstimate = (date: Date) => date.toISOString().split('T')[0];
export const getDateStringFromEstimate = (date: Date | string) => new Date(date).toISOString().split('T')[0];
const pad = (num: number) => (num < 10 ? '0' : '') + num;

// Return string in format yyyy-mm-dd from local Date

export const getDateString = (date: Date) => {
const pad = (num: number) => (num < 10 ? '0' : '') + num;
export const getDateString = (date: Date | string) => {
const parsedDate = new Date(date);

return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
return `${parsedDate.getFullYear()}-${pad(parsedDate.getMonth() + 1)}-${pad(parsedDate.getDate())}`;
};

const urlDateRangeSeparator = '~';
Expand Down Expand Up @@ -258,8 +259,9 @@ export const decodeHistoryEstimate = (data: string): { date: Date; type: DateTyp
}
};

export const calculateElapsedDays = (startDate: Date) => {
const timeDifference = new Date().getTime() - startDate.getTime();
export const calculateElapsedDays = (startDate: Date | string) => {
const date = new Date(startDate);
const timeDifference = new Date().getTime() - date.getTime();
return Math.floor(timeDifference / (1000 * 60 * 60 * 24));
};

Expand Down
13 changes: 11 additions & 2 deletions src/utils/recalculateCriteriaScore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ interface GoalCriteria extends GoalAchieveCriteria {
criteriaGoal: (Goal & { state: State | null }) | null;
}

// simple calc score value for single goal
export const calcAchievedWeight = <T extends GoalCriteria>(criteriaList: T[]): number => {
export const baseCalcCriteriaWeight = <
G extends { state: { type: StateType } | null },
T extends { deleted: boolean | null; weight: number; isDone: boolean; criteriaGoal: G | null },
>(
criteriaList: T[],
): number => {
let achivedWithWeight = 0;
let comletedWithoutWeight = 0;
let anyWithoutWeight = 0;
Expand Down Expand Up @@ -52,6 +56,11 @@ export const calcAchievedWeight = <T extends GoalCriteria>(criteriaList: T[]): n
);
};

// simple calc score value for single goal
export const calcAchievedWeight = (criteriaList: GoalCriteria[]): number => {
return baseCalcCriteriaWeight(criteriaList);
};

type GoalCalculateScore = Goal & {
goalInCriteria?: Array<GoalCriteria> | null;
goalAchiveCriteria?: Array<GoalCriteria> | null;
Expand Down
1 change: 1 addition & 0 deletions src/utils/transformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const serialize = (data: any): any => {
if (Array.isArray(data)) return data.map(serialize);
return Object.fromEntries(Object.entries(data).map(([k, v]) => [k, serialize(v)]));
}

return data;
};

Expand Down
10 changes: 10 additions & 0 deletions trpc/inferredTypes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { inferRouterOutputs } from '@trpc/server';

import { DB } from '../generated/kysely/types';

import { TrpcRouter } from './router';
import { ExtractTypeFromGenerated } from './utils';

type RouterOutputs = inferRouterOutputs<TrpcRouter>;

Expand All @@ -23,3 +26,10 @@ export type State = RouterOutputs['state']['all'][number];
export type StateType = State['type'];
export type DashboardProject = RouterOutputs['project']['getUserProjectsWithGoals']['groups'][number]['project'];
export type DashboardGoal = RouterOutputs['project']['getUserProjectsWithGoals']['groups'][number]['goals'][number];

export type DashboardProjectV2 = RouterOutputs['v2']['project']['userProjectsWithGoals']['groups'][number];
export type DashboardGoalV2 = NonNullable<DashboardProjectV2['goals']>[number];

export type ExtractDBTypes = {
[K in keyof DB]: ExtractTypeFromGenerated<DB[K]>;
};
42 changes: 12 additions & 30 deletions trpc/queries/criteria.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { jsonBuildObject } from 'kysely/helpers/postgres';
import { sql } from 'kysely';

import { db } from '../connection/kysely';
import { Activity, Ghost, Role, State, User } from '../../generated/kysely/types';
import { Activity, Ghost, Goal, State, User } from '../../generated/kysely/types';
import { ExtractTypeFromGenerated } from '../utils';

interface CriteriaParams {
id?: string;
Expand All @@ -15,30 +16,16 @@ interface Criteria {
weight: number;
isDone: boolean;
activityId: string;
criteriaGoal: {
id: string;
title: string;
projectId: string;
_shortId: string;
state:
| (Omit<State, 'createdAt' | 'updatedAt' | 'hue'> & { createdAt: Date; updatedAt: Date; hue: number })
| null;
owner: Pick<Activity, 'id'> & {
user: Omit<User, 'createdAt' | 'updatedAt' | 'active' | 'emailVerified' | 'role' | 'invitedAt'> & {
createdAt: Date;
updatedAt: Date;
invitedAt: Date | null;
active: boolean;
emailVerified: Date | null;
role: Role;
};
ghost: Omit<Ghost, 'createdAt' | 'updatedAt'> & { createdAt: Date; updatedAt: Date };
createdAt: Date;
updatedAt: Date;
ghostId: string;
settingsId: string;
};
} | null;
criteriaGoal:
| (ExtractTypeFromGenerated<Goal> & {
state: ExtractTypeFromGenerated<State> | null;
owner: ExtractTypeFromGenerated<Activity> & {
user: ExtractTypeFromGenerated<User>;
ghost: ExtractTypeFromGenerated<Ghost>;
};
_shortId: string;
})
| null;
}

export const criteriaQuery = (params: CriteriaParams = {}) => {
Expand All @@ -53,11 +40,6 @@ export const criteriaQuery = (params: CriteriaParams = {}) => {
.leftJoin('Ghost as ghost', 'activity.ghostId', 'ghost.id')
.selectAll('criteria')
.select(({ ref, fn, eb }) => [
'criteria.id',
'criteria.title',
'criteria.activityId',
'criteria.isDone',
'criteria.weight',
eb
.case()
.when('criteria.criteriaGoalId', '=', ref('criteriaGoal.id'))
Expand Down
24 changes: 8 additions & 16 deletions trpc/queries/filter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { jsonArrayFrom } from 'kysely/helpers/postgres';
import { sql } from 'kysely';

import { db } from '../connection/kysely';

Expand All @@ -11,25 +11,17 @@ interface FilterQueryParams {
export const filterQuery = ({ activityId = '', id = '', isDefault }: FilterQueryParams | void = {}) => {
return db
.selectFrom('Filter')
.select((eb) => [
'Filter.activityId',
'Filter.createdAt',
'Filter.description',
'Filter.default',
'Filter.id',
'Filter.mode',
'Filter.params',
'Filter.title',
'Filter.updatedAt',
jsonArrayFrom(
eb
.selectFrom('_filterStargizers')
.selectAll('Filter')
.select(({ exists, selectFrom, val }) => [
exists(
selectFrom('_filterStargizers')
.select(['_filterStargizers.A as id', '_filterStargizers.B as filterId'])
.whereRef('_filterStargizers.B', '=', 'Filter.id')
.$if(activityId.length > 0, (qb) => qb.where('_filterStargizers.A', '=', activityId)),
).as('stargizers'),
).as('_isStarred'),
sql<boolean>`("Filter"."activityId" = ${val(activityId)})`.as('_isOwner'),
])
.$if(activityId.length > 0, (qb) => qb.where('Filter.activityId', '=', activityId))
.$if(activityId.length > 0 && !isDefault, (qb) => qb.where('Filter.activityId', '=', activityId))
.$if(!!isDefault, (qb) => qb.where('Filter.default', 'is', true))
.$if(id.length > 0, (qb) => qb.where('Filter.id', '=', id));
};
7 changes: 1 addition & 6 deletions trpc/queries/flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,8 @@ interface FlowQueryParams {
export const flowQuery = ({ id, title = '' }: FlowQueryParams | void = {}) => {
return db
.selectFrom('Flow')
.selectAll('Flow')
.select((eb) => [
'Flow.title',
'Flow.createdAt',
'Flow.id',
'Flow.graph',
'Flow.recommended',
'Flow.updatedAt',
jsonArrayFrom(
eb
.selectFrom('State')
Expand Down
Loading

0 comments on commit 0d673a5

Please sign in to comment.