Skip to content

Commit

Permalink
fix(INTERNAL-1196): correct watchers / starred goals
Browse files Browse the repository at this point in the history
  • Loading branch information
LamaEats committed Nov 11, 2024
1 parent d23160b commit fff872b
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 31 deletions.
10 changes: 9 additions & 1 deletion src/components/ProjectGoalList/ProjectGoalList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ interface ProjectGoalListProps {
filterPreset?: FilterById;
partnershipProject?: string[];
showNoGoals?: boolean;
isOnlySubsGoals?: boolean;
}

const onGoalClickHandler = (e: React.MouseEvent) => {
Expand All @@ -27,7 +28,13 @@ const onGoalClickHandler = (e: React.MouseEvent) => {
}
};

export const ProjectGoalList: FC<ProjectGoalListProps> = ({ id, filterPreset, partnershipProject, showNoGoals }) => {
export const ProjectGoalList: FC<ProjectGoalListProps> = ({
id,
filterPreset,
partnershipProject,
showNoGoals,
isOnlySubsGoals,
}) => {
const { queryState, setTagsFilterOutside } = useUrlFilterParams({
preset: filterPreset,
});
Expand All @@ -41,6 +48,7 @@ export const ProjectGoalList: FC<ProjectGoalListProps> = ({ id, filterPreset, pa
} = trpc.v2.project.getProjectGoalsById.useInfiniteQuery(
{
id,
isOnlySubsGoals,
goalsQuery: {
...queryState,
partnershipProject: partnershipProject ?? undefined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ export const ProjectListItemConnected: FC<ProjectListItemConnectedProps> = ({
filterPreset={filterPreset}
partnershipProject={partnershipProject}
showNoGoals={showNoGoals}
isOnlySubsGoals={project._isGoalWatching || project._isGoalStarred}
/>,
)}
</TreeViewElement>
Expand Down
31 changes: 27 additions & 4 deletions trpc/queries/goalV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ interface GetGoalsQueryParams {
role: Role;
activityId: string;
projectId: string;
isOnlySubsGoals?: boolean;
limit?: number;
offset?: number;
goalsQuery?: QueryWithFilters;
Expand Down Expand Up @@ -178,14 +179,36 @@ export const getGoalsQuery = (params: GetGoalsQueryParams) =>
.end()
.as('partnershipProjects'),
])
.where(({ or, eb }) =>
or([
.where(({ or, eb, and }) => {
const baseOr = or([
eb('Goal.projectId', '=', params.projectId),
eb('Goal.id', 'in', ({ selectFrom }) =>
selectFrom('_partnershipProjects').where('B', '=', params.projectId).select('A'),
),
]),
)
]);

if (params.isOnlySubsGoals) {
return and([
baseOr,
eb('Goal.id', 'in', ({ selectFrom }) =>
selectFrom('_goalStargizers')
.select('B as id')
.where('A', '=', params.activityId)
.union(
selectFrom('_goalWatchers')
.select('B as id')
.where('A', '=', params.activityId),
)
.union(
selectFrom('_partnershipProjects')
.where('B', '=', params.projectId)
.select('A as id'),
),
),
]);
}
return baseOr;
})
.where(({ or, and, eb, selectFrom, cast, val }) => {
const { goalsQuery } = params;
const estimate: Array<Date> = [];
Expand Down
126 changes: 103 additions & 23 deletions trpc/queries/projectV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,26 @@ import { db } from '../connection/kysely';
import { Activity, DB, Role } from '../../generated/kysely/types';
import { QueryWithFilters, SortableProjectsPropertiesArray } from '../../src/schema/common';

import { mapSortParamsToTableColumns } from './goalV2';
import { getUserActivity } from './activity';

export const getProjectsByIds = (params: { in: Array<{ id: string }>; activityId: string; role: Role }) => {
return db
.with('project_goals', () =>
db
.selectFrom('Goal')
.select(['Goal.id', 'Goal.projectId'])
.$if(params.in.length > 0, (qb) =>
qb.where((eb) =>
eb.or([
eb(
'Goal.projectId',
'in',
params.in.map(({ id }) => id),
),
]),
),
),
)
.selectFrom('Project')
.leftJoin('User as user', 'Project.activityId', 'user.activityId')
.leftJoinLateral(
Expand Down Expand Up @@ -44,6 +59,22 @@ export const getProjectsByIds = (params: { in: Array<{ id: string }>; activityId
sql<boolean>`((${val(params.role === Role.ADMIN)} or "Project"."activityId" = ${val(
params.activityId,
)}) and not "Project"."personal")`.as('_isEditable'),
exists(
selectFrom('_goalWatchers')
.select('B')
.where('A', '=', params.activityId)
.whereRef('B', 'in', ({ selectFrom }) =>
selectFrom('project_goals').select('id').whereRef('projectId', '=', 'Project.id'),
),
).as('_isGoalWatching'),
exists(
selectFrom('_goalStargizers')
.select('B')
.where('A', '=', params.activityId)
.whereRef('B', 'in', ({ selectFrom }) =>
selectFrom('project_goals').select('id').whereRef('projectId', '=', 'Project.id'),
),
).as('_isGoalStarred'),
jsonBuildObject({
activityId: ref('user.activityId'),
user: fn.toJson('user'),
Expand Down Expand Up @@ -438,23 +469,7 @@ export const getUserDashboardProjects = (params: GetUserDashboardProjectsParams)
.with('goals', (db) =>
db
.selectFrom('Goal')
.selectAll('Goal')
.leftJoinLateral(
() => getUserActivity().as('participant'),
(join) =>
join.onRef('participant.id', 'in', (qb) =>
qb.selectFrom('_goalParticipants').select('A').whereRef('B', '=', 'Goal.id'),
),
)
.leftJoinLateral(
({ selectFrom }) =>
selectFrom('_GoalToTag')
.innerJoin('Tag', 'Tag.id', 'B')
.selectAll('Tag')
.whereRef('A', '=', 'Goal.id')
.as('tag'),
(join) => join.onTrue(),
)
.select(['Goal.id', 'Goal.projectId'])
.where(({ or, eb }) =>
or([
eb('Goal.id', 'in', ({ selectFrom }) => selectFrom('subs_goals').select('B')),
Expand All @@ -465,9 +480,7 @@ export const getUserDashboardProjects = (params: GetUserDashboardProjectsParams)
]),
)
.where(getGoalsFiltersWhereExpressionBuilder(params.goalsQuery))
.where('Goal.archived', 'is not', true)
.groupBy('Goal.id')
.orderBy(mapSortParamsToTableColumns(params.goalsQuery?.sort, 'Goal', params.activityId)),
.where('Goal.archived', 'is not', true),
)
.selectFrom('Project')
.leftJoinLateral(
Expand Down Expand Up @@ -528,6 +541,72 @@ export const getUserDashboardProjects = (params: GetUserDashboardProjectsParams)
.offset(params.offset || 0);
};

/**
* Если мы получаем пользовательские проекты по следующим условиям
* 1. Пользователь - владелец или участник проекта V
* 2. Пользователь - поставил звездочку или следит за проектом V
* 3. Проект является партенским по отношению к проектам пользователя владельцем которых он является
* 4. Пользователь является краним за цель в любом проекте
* 5. Пользователь поставил звездочку или подписался на цель внутри любого проекта
* 6. Пользователь является участником цели любого проекта
*/

export const getUserDashBoardProjectsAgain = (params: GetUserDashboardProjectsParams) => {
return db
.selectFrom('Project')
.selectAll('Project')
.where('Project.archived', 'is not', true)
.where(({ or, eb }) =>
or([
eb('Project.activityId', '=', params.activityId),
eb('Project.id', 'in', ({ selectFrom }) =>
selectFrom('_projectParticipants')
.select('B as id')
.where('A', '=', params.activityId)
.union(selectFrom('_projectStargizers').select('B as id').where('A', '=', params.activityId))
.union(selectFrom('_projectWatchers').select('B as id').where('A', '=', params.activityId))
.union(
selectFrom('_partnershipProjects')
.select('A as id')
.where(
'A',
'in',
selectFrom('Project')
.select('Project.id')
.where('Project.activityId', '=', params.activityId),
),
),
),
eb('Project.id', 'in', ({ selectFrom }) =>
selectFrom('Goal')
.select('Goal.projectId as id')
.where('Goal.archived', 'is not', true)
.where(({ or, eb }) =>
or([
eb('Goal.activityId', '=', params.activityId),
eb('Goal.ownerId', '=', params.activityId),
eb('Goal.id', 'in', ({ selectFrom }) =>
selectFrom('_goalParticipants')
.select('B as id')
.where('A', '=', params.activityId)
.union(
selectFrom('_goalStargizers')
.select('B as id')
.where('A', '=', params.activityId),
)
.union(
selectFrom('_goalWatchers')
.select('B as id')
.where('A', '=', params.activityId),
),
),
]),
),
),
]),
);
};

interface GetWholeGoalCountByProjectIds {
in: Array<{ id: string }>;
}
Expand All @@ -538,7 +617,7 @@ export const getWholeGoalCountByProjectIds = (params: GetWholeGoalCountByProject
.select((eb) => [
eb
.selectFrom('Goal')
.select(({ fn }) => [fn.count('Goal.id').as('count')])
.select(({ fn, cast }) => [cast(fn.count('Goal.id'), 'integer').as('count')])
.whereRef('Goal.projectId', '=', 'Project.id')
.where('Goal.archived', 'is not', true)
.as('wholeGoalsCount'),
Expand All @@ -549,7 +628,8 @@ export const getWholeGoalCountByProjectIds = (params: GetWholeGoalCountByProject
'in',
params.in.map(({ id }) => id),
),
);
)
.$castTo<{ wholeGoalsCount: number }>();
};

interface GetProjectSuggestionsParams {
Expand Down
13 changes: 10 additions & 3 deletions trpc/router/projectV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ type ProjectResponse = ExtractTypeFromGenerated<Project> & {
_isStarred: boolean;
_isOwner: boolean;
_isEditable: boolean;
_isGoalWatching: boolean;
_isGoalStarred: boolean;
activity: ProjectActivity;
participants: ProjectActivity[] | null;
goals?: any[]; // this prop is overrides below
Expand Down Expand Up @@ -221,7 +223,7 @@ export const project = router({
})
.$castTo<ProjectResponse>()
.execute(),
getWholeGoalCountByProjectIds({ in: projectIds }).executeTakeFirst(),
getWholeGoalCountByProjectIds({ in: projectIds }).execute(),
]);

const projectsExtendedDataMap = new Map(extendedProjects.map((project) => [project.id, project]));
Expand All @@ -246,7 +248,10 @@ export const project = router({
limit,
offset: dashboardProjects.length < limit + 1 ? undefined : offset + (limit ?? 0),
},
totalGoalsCount: goalsCountsByProjects?.wholeGoalsCount ?? 0,
totalGoalsCount: (goalsCountsByProjects || []).reduce(
(acc, count) => acc + (count?.wholeGoalsCount ?? 0),
0,
),
};
}),

Expand Down Expand Up @@ -399,18 +404,20 @@ export const project = router({
.input(
z.object({
id: z.string(),
isOnlySubsGoals: z.boolean().optional(),
limit: z.number().optional(),
cursor: z.number().optional(),
goalsQuery: queryWithFiltersSchema.optional(),
}),
)
.query(async ({ input, ctx }) => {
const { limit = 10, cursor: offset = 0, goalsQuery, id } = input;
const { limit = 10, cursor: offset = 0, goalsQuery, id, isOnlySubsGoals } = input;
if (input.goalsQuery?.sort?.some(({ key }) => key === 'rank')) {
await recalculateGoalRanksIfNeeded(id, ctx.session.user.activityId);
}
const goalsByProjectQuery = getGoalsQuery({
...ctx.session.user,
isOnlySubsGoals,
projectId: id,
limit: limit + 1,
offset,
Expand Down

0 comments on commit fff872b

Please sign in to comment.