diff --git a/packages/api/schema.gql b/packages/api/schema.gql index e61731c..c0ff346 100644 --- a/packages/api/schema.gql +++ b/packages/api/schema.gql @@ -3,6 +3,7 @@ type Comment { id: ID! text: String user: UserInterface! + published: Boolean! } """ @@ -24,6 +25,20 @@ type CreateCommentPayload { commentable: CommentableInterface! } +type UpdateCommentPayload { + comment: Comment! + commentable: CommentableInterface! +} + +type DeleteCommentPayload { + comment: Comment! + commentable: CommentableInterface! +} + +type PublishCommentsPayload { + report: Report! +} + type Day implements CommentableInterface { comments: [Comment!]! createdAt: String! @@ -129,6 +144,41 @@ type Mutation { """ createCommentOnReport(text: String!, id: ID!, traineeId: ID!): CreateCommentPayload! + """ + Updates a comment on a Day which is identified by the id argument. + """ + updateCommentOnDay(text: String!, id: ID!, traineeId: ID!, commentId: ID!): UpdateCommentPayload! + + """ + Updates a comment on a Entry which is identified by the id argument. + """ + updateCommentOnEntry(text: String!, id: ID!, traineeId: ID!, commentId: ID!): UpdateCommentPayload! + + """ + Updates a comment on a Report which is identified by the id argument. + """ + updateCommentOnReport(text: String!, id: ID!, traineeId: ID!, commentId: ID!): UpdateCommentPayload! + + """ + Deletes a comment on a Day which is identified by the id argument. + """ + deleteCommentOnDay(id: ID!, traineeId: ID!, commentId: ID!): DeleteCommentPayload! + + """ + Deletes a comment on a Entry which is identified by the id argument. + """ + deleteCommentOnEntry(id: ID!, traineeId: ID!, commentId: ID!): DeleteCommentPayload! + + """ + Deletes a comment on a Report which is identified by the id argument. + """ + deleteCommentOnReport(id: ID!, traineeId: ID!, commentId: ID!): DeleteCommentPayload! + + """ + Publishes all comments on a report which is identified by the id argument. + """ + publishAllComments(id: ID!, traineeId: ID!): PublishCommentsPayload! + """ Creates a new entry which is assigned to the matching report based on the day Id """ diff --git a/packages/api/src/graphql.ts b/packages/api/src/graphql.ts index 9740ac0..a38c425 100644 --- a/packages/api/src/graphql.ts +++ b/packages/api/src/graphql.ts @@ -39,6 +39,7 @@ export type GqlComment = { __typename?: 'Comment'; createdAt: Scalars['String']['output']; id: Scalars['ID']['output']; + published: Scalars['Boolean']['output']; text?: Maybe; user: GqlUserInterface; }; @@ -106,6 +107,12 @@ export type GqlDayStatusEnum = /** workday */ | 'work'; +export type GqlDeleteCommentPayload = { + __typename?: 'DeleteCommentPayload'; + comment: GqlComment; + commentable: GqlCommentableInterface; +}; + /** Autogenerated return type of DevSetUser */ export type GqlDevSetUserPayload = { __typename?: 'DevSetUserPayload'; @@ -170,6 +177,12 @@ export type GqlMutation = { createTrainee?: Maybe; /** Creates Trainer. */ createTrainer?: Maybe; + /** Deletes a comment on a Day which is identified by the id argument. */ + deleteCommentOnDay: GqlDeleteCommentPayload; + /** Deletes a comment on a Entry which is identified by the id argument. */ + deleteCommentOnEntry: GqlDeleteCommentPayload; + /** Deletes a comment on a Report which is identified by the id argument. */ + deleteCommentOnReport: GqlDeleteCommentPayload; /** Deletes an entry by the given ID. Only considers entries made by the current user. Returns the ID of the deleted entry. */ deleteEntry: GqlMutateEntryPayload; /** Get Avatar Bucket Upload URL */ @@ -180,6 +193,8 @@ export type GqlMutation = { login?: Maybe; /** Marks User to be deleted */ markUserForDeletion?: Maybe; + /** Publishes all comments on a report which is identified by the id argument. */ + publishAllComments: GqlPublishCommentsPayload; /** Unclaims a Trainee by the current Trainer */ unclaimTrainee?: Maybe; /** Unlink Alexa account */ @@ -188,6 +203,12 @@ export type GqlMutation = { unmarkUserForDeletion?: Maybe; /** Updates Admin. */ updateAdmin?: Maybe; + /** Updates a comment on a Day which is identified by the id argument. */ + updateCommentOnDay: GqlUpdateCommentPayload; + /** Updates a comment on a Entry which is identified by the id argument. */ + updateCommentOnEntry: GqlUpdateCommentPayload; + /** Updates a comment on a Report which is identified by the id argument. */ + updateCommentOnReport: GqlUpdateCommentPayload; /** Updates the current trainee */ updateCurrentTrainee?: Maybe; /** Updates the current user */ @@ -262,6 +283,27 @@ export type GqlMutationCreateTrainerArgs = { }; +export type GqlMutationDeleteCommentOnDayArgs = { + commentId: Scalars['ID']['input']; + id: Scalars['ID']['input']; + traineeId: Scalars['ID']['input']; +}; + + +export type GqlMutationDeleteCommentOnEntryArgs = { + commentId: Scalars['ID']['input']; + id: Scalars['ID']['input']; + traineeId: Scalars['ID']['input']; +}; + + +export type GqlMutationDeleteCommentOnReportArgs = { + commentId: Scalars['ID']['input']; + id: Scalars['ID']['input']; + traineeId: Scalars['ID']['input']; +}; + + export type GqlMutationDeleteEntryArgs = { id: Scalars['ID']['input']; }; @@ -288,6 +330,12 @@ export type GqlMutationMarkUserForDeletionArgs = { }; +export type GqlMutationPublishAllCommentsArgs = { + id: Scalars['ID']['input']; + traineeId: Scalars['ID']['input']; +}; + + export type GqlMutationUnclaimTraineeArgs = { id: Scalars['ID']['input']; }; @@ -304,6 +352,30 @@ export type GqlMutationUpdateAdminArgs = { }; +export type GqlMutationUpdateCommentOnDayArgs = { + commentId: Scalars['ID']['input']; + id: Scalars['ID']['input']; + text: Scalars['String']['input']; + traineeId: Scalars['ID']['input']; +}; + + +export type GqlMutationUpdateCommentOnEntryArgs = { + commentId: Scalars['ID']['input']; + id: Scalars['ID']['input']; + text: Scalars['String']['input']; + traineeId: Scalars['ID']['input']; +}; + + +export type GqlMutationUpdateCommentOnReportArgs = { + commentId: Scalars['ID']['input']; + id: Scalars['ID']['input']; + text: Scalars['String']['input']; + traineeId: Scalars['ID']['input']; +}; + + export type GqlMutationUpdateCurrentTraineeArgs = { input: GqlUpdateCurrentTraineeInput; }; @@ -364,6 +436,11 @@ export type GqlPrintPayload = { estimatedWaitingTime: Scalars['Int']['output']; }; +export type GqlPublishCommentsPayload = { + __typename?: 'PublishCommentsPayload'; + report: GqlReport; +}; + export type GqlQuery = { __typename?: 'Query'; /** Get all Admins */ @@ -509,6 +586,12 @@ export type GqlUpdateAdminInput = { lastName?: InputMaybe; }; +export type GqlUpdateCommentPayload = { + __typename?: 'UpdateCommentPayload'; + comment: GqlComment; + commentable: GqlCommentableInterface; +}; + export type GqlUpdateCurrentTraineeInput = { course?: InputMaybe; }; @@ -647,6 +730,7 @@ export type GqlResolversTypes = ResolversObject<{ CreateTrainerInput: GqlCreateTrainerInput; Day: ResolverTypeWrapper; DayStatusEnum: GqlDayStatusEnum; + DeleteCommentPayload: ResolverTypeWrapper & { comment: GqlResolversTypes['Comment'], commentable: GqlResolversTypes['CommentableInterface'] }>; DevSetUserPayload: ResolverTypeWrapper & { user?: Maybe }>; Entry: ResolverTypeWrapper; EntryInput: GqlEntryInput; @@ -657,6 +741,7 @@ export type GqlResolversTypes = ResolversObject<{ Mutation: ResolverTypeWrapper<{}>; OAuthPayload: ResolverTypeWrapper; PrintPayload: ResolverTypeWrapper; + PublishCommentsPayload: ResolverTypeWrapper & { report: GqlResolversTypes['Report'] }>; Query: ResolverTypeWrapper<{}>; Report: ResolverTypeWrapper; ReportStatus: GqlReportStatus; @@ -666,6 +751,7 @@ export type GqlResolversTypes = ResolversObject<{ Trainer: ResolverTypeWrapper; TrainerTraineePayload: ResolverTypeWrapper & { trainee: GqlResolversTypes['Trainee'], trainer: GqlResolversTypes['Trainer'] }>; UpdateAdminInput: GqlUpdateAdminInput; + UpdateCommentPayload: ResolverTypeWrapper & { comment: GqlResolversTypes['Comment'], commentable: GqlResolversTypes['CommentableInterface'] }>; UpdateCurrentTraineeInput: GqlUpdateCurrentTraineeInput; UpdateReportPayload: ResolverTypeWrapper & { report: GqlResolversTypes['Report'], trainee: GqlResolversTypes['Trainee'] }>; UpdateTraineeInput: GqlUpdateTraineeInput; @@ -687,6 +773,7 @@ export type GqlResolversParentTypes = ResolversObject<{ CreateTraineeInput: GqlCreateTraineeInput; CreateTrainerInput: GqlCreateTrainerInput; Day: Day; + DeleteCommentPayload: Omit & { comment: GqlResolversParentTypes['Comment'], commentable: GqlResolversParentTypes['CommentableInterface'] }; DevSetUserPayload: Omit & { user?: Maybe }; Entry: Entry; EntryInput: GqlEntryInput; @@ -697,6 +784,7 @@ export type GqlResolversParentTypes = ResolversObject<{ Mutation: {}; OAuthPayload: GqlOAuthPayload; PrintPayload: GqlPrintPayload; + PublishCommentsPayload: Omit & { report: GqlResolversParentTypes['Report'] }; Query: {}; Report: Report; String: Scalars['String']['output']; @@ -705,6 +793,7 @@ export type GqlResolversParentTypes = ResolversObject<{ Trainer: Trainer; TrainerTraineePayload: Omit & { trainee: GqlResolversParentTypes['Trainee'], trainer: GqlResolversParentTypes['Trainer'] }; UpdateAdminInput: GqlUpdateAdminInput; + UpdateCommentPayload: Omit & { comment: GqlResolversParentTypes['Comment'], commentable: GqlResolversParentTypes['CommentableInterface'] }; UpdateCurrentTraineeInput: GqlUpdateCurrentTraineeInput; UpdateReportPayload: Omit & { report: GqlResolversParentTypes['Report'], trainee: GqlResolversParentTypes['Trainee'] }; UpdateTraineeInput: GqlUpdateTraineeInput; @@ -732,6 +821,7 @@ export type GqlAdminResolvers = ResolversObject<{ createdAt?: Resolver; id?: Resolver; + published?: Resolver; text?: Resolver, ParentType, ContextType>; user?: Resolver; __isTypeOf?: IsTypeOfResolverFn; @@ -766,6 +856,12 @@ export type GqlDayResolvers; }>; +export type GqlDeleteCommentPayloadResolvers = ResolversObject<{ + comment?: Resolver; + commentable?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + export type GqlDevSetUserPayloadResolvers = ResolversObject<{ user?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; @@ -812,15 +908,22 @@ export type GqlMutationResolvers; createTrainee?: Resolver, ParentType, ContextType, RequireFields>; createTrainer?: Resolver, ParentType, ContextType, RequireFields>; + deleteCommentOnDay?: Resolver>; + deleteCommentOnEntry?: Resolver>; + deleteCommentOnReport?: Resolver>; deleteEntry?: Resolver>; getAvatarSignedUrl?: Resolver, ParentType, ContextType, RequireFields>; linkAlexa?: Resolver, ParentType, ContextType, RequireFields>; login?: Resolver, ParentType, ContextType, RequireFields>; markUserForDeletion?: Resolver, ParentType, ContextType, RequireFields>; + publishAllComments?: Resolver>; unclaimTrainee?: Resolver, ParentType, ContextType, RequireFields>; unlinkAlexa?: Resolver, ParentType, ContextType>; unmarkUserForDeletion?: Resolver, ParentType, ContextType, RequireFields>; updateAdmin?: Resolver, ParentType, ContextType, RequireFields>; + updateCommentOnDay?: Resolver>; + updateCommentOnEntry?: Resolver>; + updateCommentOnReport?: Resolver>; updateCurrentTrainee?: Resolver, ParentType, ContextType, RequireFields>; updateCurrentUser?: Resolver, ParentType, ContextType, Partial>; updateDay?: Resolver, ParentType, ContextType, RequireFields>; @@ -843,6 +946,11 @@ export type GqlPrintPayloadResolvers; }>; +export type GqlPublishCommentsPayloadResolvers = ResolversObject<{ + report?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + export type GqlQueryResolvers = ResolversObject<{ admins?: Resolver, ParentType, ContextType>; alexaLinkingUrl?: Resolver, ParentType, ContextType>; @@ -930,6 +1038,12 @@ export type GqlTrainerTraineePayloadResolvers; }>; +export type GqlUpdateCommentPayloadResolvers = ResolversObject<{ + comment?: Resolver; + commentable?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}>; + export type GqlUpdateReportPayloadResolvers = ResolversObject<{ report?: Resolver; trainee?: Resolver; @@ -958,6 +1072,7 @@ export type GqlResolvers = ResolversObject<{ Company?: GqlCompanyResolvers; CreateCommentPayload?: GqlCreateCommentPayloadResolvers; Day?: GqlDayResolvers; + DeleteCommentPayload?: GqlDeleteCommentPayloadResolvers; DevSetUserPayload?: GqlDevSetUserPayloadResolvers; Entry?: GqlEntryResolvers; LaraConfig?: GqlLaraConfigResolvers; @@ -965,12 +1080,14 @@ export type GqlResolvers = ResolversObject<{ Mutation?: GqlMutationResolvers; OAuthPayload?: GqlOAuthPayloadResolvers; PrintPayload?: GqlPrintPayloadResolvers; + PublishCommentsPayload?: GqlPublishCommentsPayloadResolvers; Query?: GqlQueryResolvers; Report?: GqlReportResolvers; Suggestion?: GqlSuggestionResolvers; Trainee?: GqlTraineeResolvers; Trainer?: GqlTrainerResolvers; TrainerTraineePayload?: GqlTrainerTraineePayloadResolvers; + UpdateCommentPayload?: GqlUpdateCommentPayloadResolvers; UpdateReportPayload?: GqlUpdateReportPayloadResolvers; UserInterface?: GqlUserInterfaceResolvers; }>; diff --git a/packages/backend/src/i18n/de.ts b/packages/backend/src/i18n/de.ts index 52d9995..ba8d319 100644 --- a/packages/backend/src/i18n/de.ts +++ b/packages/backend/src/i18n/de.ts @@ -13,6 +13,7 @@ export const GermanTranslations: Translations = { missingReport: 'Bericht konnte nicht gefunden werden', missingDay: 'Tag konnte nicht gefunden werden', missingEntry: 'Eintrag konnte nicht gefunden werden', + missingComment: 'Kommentar konnte nicht gefunden werden', wrongReportStatus: 'Der Bericht hat den falschen Status', wrongDayStatus: 'Der Tag hat den falschen Status', userAlreadyExists: 'Ein Benutzer mit dieser Email existiert bereits', @@ -26,6 +27,7 @@ export const GermanTranslations: Translations = { missingPeriod: 'Die Ausbildungsperiode fehlt', cantDeleteYourself: 'Ein Admin kann sich nicht selber für die Löschung markieren', cantChangeOwnEmail: 'Ein Admin kann seine eigene E-Mail Adresse nicht ändern', + cantEditPublishedComment: 'Veröffentlichte Kommentare können nicht mehr editiert werden', }, email: { hello: 'Hallo', diff --git a/packages/backend/src/i18n/en.ts b/packages/backend/src/i18n/en.ts index bc34b05..62fed70 100644 --- a/packages/backend/src/i18n/en.ts +++ b/packages/backend/src/i18n/en.ts @@ -13,6 +13,7 @@ export const EnglishTranslations: Translations = { missingReport: "clouldn't find report", missingDay: "clouldn't find day", missingEntry: "couldn't find entry", + missingComment: "couldn't find comment", wrongReportStatus: 'wrong report status', wrongDayStatus: 'wrong Day status', userAlreadyExists: 'User with this Email already exists', @@ -26,6 +27,7 @@ export const EnglishTranslations: Translations = { missingPeriod: 'Missing period', cantDeleteYourself: "An Admin can't mark themselves for deletion", cantChangeOwnEmail: "An Admin can't change their own e-mail address", + cantEditPublishedComment: 'Published Comments can not be edited', }, email: { hello: 'Hello', diff --git a/packages/backend/src/i18n/index.ts b/packages/backend/src/i18n/index.ts index 47297bd..529fdb6 100644 --- a/packages/backend/src/i18n/index.ts +++ b/packages/backend/src/i18n/index.ts @@ -17,6 +17,7 @@ export type Translations = { missingReport: string missingDay: string missingEntry: string + missingComment: string wrongReportStatus: string wrongDayStatus: string userAlreadyExists: string @@ -30,6 +31,7 @@ export type Translations = { missingPeriod: string cantDeleteYourself: string cantChangeOwnEmail: string + cantEditPublishedComment: string } email: EmailTranslations print: PrintTranslations diff --git a/packages/backend/src/resolvers/comment.resolver.ts b/packages/backend/src/resolvers/comment.resolver.ts index 94e4ffe..48ebdfc 100644 --- a/packages/backend/src/resolvers/comment.resolver.ts +++ b/packages/backend/src/resolvers/comment.resolver.ts @@ -4,7 +4,13 @@ import { AuthenticatedContext, GqlResolvers } from '@lara/api' import { reportById } from '../repositories/report.repo' import { userById } from '../repositories/user.repo' -import { commentableReports, createCommentOnCommentable } from '../services/comment.service' +import { + commentableReports, + createCommentOnCommentable, + deleteCommentOnCommentable, + publishCommentsOnReport, + updateCommentOnCommentable, +} from '../services/comment.service' import { reportDayByDayId } from '../services/day.service' import { reportDayEntryByEntryId } from '../services/entry.service' import { t } from '../i18n' @@ -71,5 +77,92 @@ export const commentResolver: GqlResolvers = { report, }) }, + updateCommentOnDay: async (_parent, { id, text, traineeId, commentId }, { currentUser }) => { + const reports = await commentableReports(traineeId) + const { report, day } = reportDayByDayId(id, reports) + + return updateCommentOnCommentable({ + commentable: day, + text, + currentUser, + report, + commentId, + }) + }, + updateCommentOnEntry: async (_parent, { id, text, traineeId, commentId }, { currentUser }) => { + const reports = await commentableReports(traineeId) + const { report, entry } = reportDayEntryByEntryId(id, reports) + + return updateCommentOnCommentable({ + commentable: entry, + text, + currentUser, + report, + commentId, + }) + }, + updateCommentOnReport: async (_parent, { id, text, traineeId, commentId }, { currentUser }) => { + const report = await reportById(id) + + if (report?.traineeId !== traineeId) { + throw new GraphQLError(t('errors.missingReport', currentUser.language)) + } + + return updateCommentOnCommentable({ + commentable: report, + text, + currentUser, + report, + commentId, + }) + }, + deleteCommentOnDay: async (_parent, { id, traineeId, commentId }, { currentUser }) => { + const reports = await commentableReports(traineeId) + const { report, day } = reportDayByDayId(id, reports) + + return deleteCommentOnCommentable({ + commentable: day, + currentUser, + report, + commentId, + }) + }, + deleteCommentOnEntry: async (_parent, { id, traineeId, commentId }, { currentUser }) => { + const reports = await commentableReports(traineeId) + const { report, entry } = reportDayEntryByEntryId(id, reports) + + return deleteCommentOnCommentable({ + commentable: entry, + currentUser, + report, + commentId, + }) + }, + deleteCommentOnReport: async (_parent, { id, traineeId, commentId }, { currentUser }) => { + const report = await reportById(id) + + if (report?.traineeId !== traineeId) { + throw new GraphQLError(t('errors.missingReport', currentUser.language)) + } + + return deleteCommentOnCommentable({ + commentable: report, + currentUser, + report, + commentId, + }) + }, + publishAllComments: async (_parent, { id, traineeId }, { currentUser }) => { + const report = await reportById(id) + + if (report?.traineeId !== traineeId) { + throw new GraphQLError(t('errors.missingReport', currentUser.language)) + } + + return publishCommentsOnReport({ + currentUser, + report, + }) + }, }, } diff --git a/packages/backend/src/resolvers/report.resolver.ts b/packages/backend/src/resolvers/report.resolver.ts index a384d29..afca498 100644 --- a/packages/backend/src/resolvers/report.resolver.ts +++ b/packages/backend/src/resolvers/report.resolver.ts @@ -75,6 +75,20 @@ export const reportTraineeResolver: GqlResolvers = { : report } + if (report && report.status === 'review') + return { + ...report, + comments: report.comments.filter((com) => com.published), + days: report.days.map((day) => ({ + ...day, + entries: day.entries.map((entry) => ({ + ...entry, + comments: entry.comments.filter((com) => com.published), + })), + comments: day.comments.filter((com) => com.published), + })), + } + return report }, }, diff --git a/packages/backend/src/services/comment.service.ts b/packages/backend/src/services/comment.service.ts index a470a75..12cfe70 100644 --- a/packages/backend/src/services/comment.service.ts +++ b/packages/backend/src/services/comment.service.ts @@ -20,6 +20,7 @@ export const generateComment = (text: string, user: User): Comment => { createdAt: new Date().toISOString(), userId: user.id, text, + published: false, } } @@ -62,6 +63,133 @@ export const createCommentOnCommentable = async ({ } } +type UpdateCommentOnCommentableOptions = { + commentable?: CommentableInterface + report?: Report + text: string + currentUser: User + commentId: string +} + +/** + * Abstract method to update comments for entries, days and reports + * @param options Data for updating a comment + * @returns GQL update comment payload + */ +export const updateCommentOnCommentable = async ({ + commentable, + text, + report, + currentUser, + commentId, +}: UpdateCommentOnCommentableOptions): Promise => { + const t = createT(currentUser.language) + + if (!report) { + throw new GraphQLError(t('errors.missingReport')) + } + + if (!commentable) { + throw new GraphQLError(t('errors.missingCommentable')) + } + + const comment = commentable.comments.find((com) => com.id === commentId) + if (!comment) { + throw new GraphQLError(t('errors.missingComment')) + } + if (comment.published) { + throw new GraphQLError(t('errors.cantEditPublishedComment')) + } + comment.text = text + + await updateReport(report, { updateKeys: ['days', 'comments'] }) + + return { + comment, + commentable, + } +} + +type DeleteCommentOnCommentableOptions = { + commentable?: CommentableInterface + report?: Report + currentUser: User + commentId: string +} + +/** + * Abstract method to delete comments for entries, days and reports + * @param options Data for deleting a comment + * @returns GQL delete comment payload + */ +export const deleteCommentOnCommentable = async ({ + commentable, + report, + currentUser, + commentId, +}: DeleteCommentOnCommentableOptions): Promise => { + const t = createT(currentUser.language) + + if (!report) { + throw new GraphQLError(t('errors.missingReport')) + } + + if (!commentable) { + throw new GraphQLError(t('errors.missingCommentable')) + } + + const comment = commentable.comments.find((com) => com.id === commentId) + if (!comment) { + throw new GraphQLError(t('errors.missingComment')) + } + if (comment.published) { + throw new GraphQLError(t('errors.cantEditPublishedComment')) + } + commentable.comments = commentable.comments.filter((com) => com.id !== comment.id) + + await updateReport(report, { updateKeys: ['days', 'comments'] }) + + return { + comment, + commentable, + } +} + +type PublishCommenstOnReportOptions = { + report?: Report + currentUser: User +} + +/** + * Abstract method to publish all comments on a report + * @param options Data for publishing comments + * @returns GQL publish comments payload + */ +export const publishCommentsOnReport = async ({ + report, + currentUser, +}: PublishCommenstOnReportOptions): Promise => { + const t = createT(currentUser.language) + + if (!report) { + throw new GraphQLError(t('errors.missingReport')) + } + + report.comments.forEach((com) => (com.published = true)) + report.days.forEach((day) => { + day.comments.forEach((com) => (com.published = true)) + day.entries.forEach((entry) => { + entry.comments.forEach((com) => (com.published = true)) + }) + }) + + await updateReport(report, { updateKeys: ['days', 'comments'] }) + + return { + report, + } +} + export const commentableReports = async (traineeId: string): Promise => { const trainee = await traineeById(traineeId) diff --git a/packages/components/package.json b/packages/components/package.json index 83b416c..a42d76e 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -13,6 +13,7 @@ "@rebass/grid": "^6.1.0", "react": "^19.1.1", "react-dom": "^19.1.1", + "react-localization": "^2.0.6", "styled-components": "^6.1.19", "styled-modern-normalize": "^0.2.0" }, diff --git a/packages/components/src/comment-bubble-layout.tsx b/packages/components/src/comment-bubble-layout.tsx index 4a4fe98..b0e07fc 100644 --- a/packages/components/src/comment-bubble-layout.tsx +++ b/packages/components/src/comment-bubble-layout.tsx @@ -1,4 +1,4 @@ -import React, { JSX } from 'react' +import React, { JSX, useState } from 'react' import styled from 'styled-components' import { BorderRadii } from './border-radius' @@ -6,6 +6,7 @@ import { FontSizes } from './font-size' import { Spacings } from './spacing' const MessageContainer = styled.div<{ right?: boolean }>` + position: relative; display: flex; padding: ${Spacings.m} ${Spacings.l}; flex-direction: ${(props) => (props.right ? 'row-reverse' : 'row')}; @@ -42,19 +43,74 @@ const Author = styled.span` display: block; ` +const MessageInput = styled.input` + all: unset; + width: 100%; + height: 28px; + border-bottom: 1px solid ${(props) => props.theme.inputBorderEmpty}; + border-radius: 2px; + transition: border-bottom 0.2s; + + &:hover { + border-bottom: 1px solid ${(props) => props.theme.inputBorderSaved}; + } +` + interface CommentBubbleLayoutProps { avatar?: JSX.Element author?: string message?: string right?: boolean + updateMessage?: (message: string, commentId: string) => void + commentId?: string } -export const CommentBubbleLayout: React.FC = ({ avatar, author, message, right }) => { +export const CommentBubbleLayout: React.FC = ({ + avatar, + author, + message, + right, + updateMessage, + commentId, +}) => { + const [msg, setMsg] = useState(message) + + const updateComment = (newMsg: string) => { + if (updateMessage) updateMessage(newMsg, commentId ?? '') + } + + const handleKeyDown = (event: React.KeyboardEvent) => { + const target = event.target as HTMLInputElement + const key = event.key + + if (key === 'Enter') { + target.blur() + } + } + + const handleBlur = (event: React.FocusEvent) => { + const target = event.target as HTMLInputElement + if (target.value === message && target.value !== '') return + console.log(commentId + ' UPDATE: ' + message + ' => ' + target.value) + updateComment(target.value) + } + return ( {author}: - {message} + {updateMessage ? ( + { + setMsg(e.target.value) + }} + onKeyDown={handleKeyDown} + onBlur={handleBlur} + /> + ) : ( + message + )} {avatar} diff --git a/packages/frontend/src/components/comment-box.tsx b/packages/frontend/src/components/comment-box.tsx index 88fc0cb..a00b8c6 100644 --- a/packages/frontend/src/components/comment-box.tsx +++ b/packages/frontend/src/components/comment-box.tsx @@ -5,12 +5,13 @@ import CommentBubble from './comment-bubble' import Loader from './loader' interface CommentBoxProps { - comments?: (Pick & { + comments?: (Pick & { user: Pick })[] + updateMessage?: (message: string, commentId: string) => void } -const CommentBox: React.FunctionComponent = ({ comments }) => { +const CommentBox: React.FunctionComponent = ({ comments, updateMessage }) => { const { data, loading } = useCommentBoxDataQuery() if (loading || !data) { @@ -22,13 +23,15 @@ const CommentBox: React.FunctionComponent = ({ comments }) => { return ( <> {comments - ? comments.map((comment, index) => ( + ? comments.map((comment) => ( )) : null} diff --git a/packages/frontend/src/components/comment-bubble.tsx b/packages/frontend/src/components/comment-bubble.tsx index ed95b2d..801eee1 100644 --- a/packages/frontend/src/components/comment-bubble.tsx +++ b/packages/frontend/src/components/comment-bubble.tsx @@ -9,15 +9,26 @@ interface CommentBubbleProps { author?: string message?: string right?: boolean + updateMessage?: (message: string, commentId: string) => void + commentId?: string } -const CommentBubble: React.FunctionComponent = ({ id, author, message, right }) => { +const CommentBubble: React.FunctionComponent = ({ + id, + author, + message, + right, + updateMessage, + commentId, +}) => { return ( {id && }} author={author} message={message} right={right} + updateMessage={updateMessage} + commentId={commentId} > ) } diff --git a/packages/frontend/src/components/comment-section.tsx b/packages/frontend/src/components/comment-section.tsx index 5eaf49c..d184f38 100644 --- a/packages/frontend/src/components/comment-section.tsx +++ b/packages/frontend/src/components/comment-section.tsx @@ -8,12 +8,13 @@ import strings from '../locales/localization' import CommentBox from './comment-box' interface CommentSectionProps { - comments: (Pick & { + comments: (Pick & { user: Pick })[] onSubmit: onSubmitType displayTextInput: boolean bottomSpace?: boolean + updateMessage?: (message: string, commentId: string) => void } type onSubmitType = (comment: string) => void @@ -23,6 +24,7 @@ const CommentSection: React.FunctionComponent = ({ bottomSpace, displayTextInput, onSubmit: submit, + updateMessage, }) => { const { handleSubmit, @@ -32,16 +34,17 @@ const CommentSection: React.FunctionComponent = ({ } = useForm<{ comment: string }>() const onSubmit = handleSubmit((formData) => { + if (formData.comment.trim() === '') return submit(formData.comment) void setValue('comment', '') }) return ( <> - + {displayTextInput && ( -
+ {strings.report.comments.addComment} & { - comments: (Pick & { + comments: (Pick & { user: Pick })[] } & { entries: (Pick & { - comments: (Pick & { + comments: (Pick & { user: Pick })[] })[] @@ -65,10 +66,29 @@ interface DayInputProps { disabled?: boolean reportStatus?: ReportStatus primary?: boolean + updateMessageDay?: (message: string, commentId: string) => void + updateMessageEntry?: ( + message: string, + commentId: string, + entry: Pick & { + comments: (Pick & { + user: Pick + })[] + } + ) => void } -const DayInput: React.FunctionComponent = ({ day, heading, disabled, reportStatus, primary }) => { +const DayInput: React.FunctionComponent = ({ + day, + heading, + disabled, + reportStatus, + primary, + updateMessageDay, + updateMessageEntry, +}) => { const { getTotalMinutes } = useDayHelper() + const { addToast } = useToastContext() const { loading, data } = useDayInputDataQuery() const [createComment] = useCreateCommentOnDayMutation() @@ -143,11 +163,19 @@ const DayInput: React.FunctionComponent = ({ day, heading, disabl id: 'null', text, user: data.currentUser, + published: false, }, ], }, }, }, + }).then(() => { + addToast({ + icon: 'Comment', + title: strings.trainerReportOverview.reportCommentSuccessTitle, + text: strings.trainerReportOverview.reportCommentSuccess, + type: 'success', + }) }) } @@ -194,7 +222,12 @@ const DayInput: React.FunctionComponent = ({ day, heading, disabl total={day && } commentsection={ reportStatus !== ReportStatus.Todo && day ? ( - + ) : undefined } > @@ -204,6 +237,7 @@ const DayInput: React.FunctionComponent = ({ day, heading, disabl reportStatus={reportStatus ?? ReportStatus.Todo} disabled={Boolean(disabled)} trainee={data.currentUser} + updateMessage={updateMessageEntry} /> ) diff --git a/packages/frontend/src/components/entries-input.tsx b/packages/frontend/src/components/entries-input.tsx index 2ef4c86..3f78ed8 100644 --- a/packages/frontend/src/components/entries-input.tsx +++ b/packages/frontend/src/components/entries-input.tsx @@ -22,7 +22,7 @@ import { useDayHelper } from '../helper/day-helper' interface EntriesInputProps { day?: Pick & { entries: (Pick & { - comments: (Pick & { + comments: (Pick & { user: Pick })[] })[] @@ -31,9 +31,25 @@ interface EntriesInputProps { reportStatus: ReportStatus disabled: boolean handleStatusChange: (status: EntryStatusType) => void + updateMessage?: ( + message: string, + commentId: string, + entry: Pick & { + comments: (Pick & { + user: Pick + })[] + } + ) => void } -const EntriesInput: React.FC = ({ day, disabled, reportStatus, handleStatusChange, trainee }) => { +const EntriesInput: React.FC = ({ + day, + disabled, + reportStatus, + handleStatusChange, + trainee, + updateMessage, +}) => { const [createEntryMutation] = useCreateEntryMutation() const { addToast } = useToastContext() const [showContextMenu, setShowContextMenu] = React.useState('') @@ -100,6 +116,7 @@ const EntriesInput: React.FC = ({ day, disabled, reportStatus trainee={trainee} showContextMenu={showContextMenu} setShowContextMenu={setShowContextMenu} + updateMessage={updateMessage ? (msg, commentId) => updateMessage(msg, commentId, entry) : undefined} /> ))} {!disabled && } diff --git a/packages/frontend/src/components/entry-input.tsx b/packages/frontend/src/components/entry-input.tsx index e904dff..069de1a 100644 --- a/packages/frontend/src/components/entry-input.tsx +++ b/packages/frontend/src/components/entry-input.tsx @@ -42,7 +42,7 @@ interface EntryDisplayFieldProps { entries: Pick[] } entry: Pick & { - comments: (Pick & { + comments: (Pick & { user: Pick })[] } @@ -52,6 +52,7 @@ interface EntryDisplayFieldProps { handleStatusChange?: (status: EntryStatusType) => void showContextMenu?: string setShowContextMenu?: React.Dispatch> + updateMessage?: (message: string, commentId: string) => void } const EntryInput: React.FC = ({ @@ -63,6 +64,7 @@ const EntryInput: React.FC = ({ trainee, showContextMenu, setShowContextMenu, + updateMessage, }) => { const { loading, data } = useEntryInputDataQuery() @@ -94,6 +96,7 @@ const EntryInput: React.FC = ({ const key = event.key if (key === 'Enter') { + if (target.value.trim() === '') return commentOnEntry(target.value) target.value = '' @@ -101,6 +104,15 @@ const EntryInput: React.FC = ({ } } + const handleBlur = (event: React.FocusEvent) => { + const target = event.target as HTMLInputElement + if (target.value.trim() === '') return + commentOnEntry(target.value) + + target.value = '' + toggleCommentInput() + } + const commentOnEntry = (text: string) => { if (!data) { return @@ -130,11 +142,19 @@ const EntryInput: React.FC = ({ id: '', text, user, + published: false, }, ], }, }, }, + }).then(() => { + addToast({ + icon: 'Comment', + title: strings.trainerReportOverview.reportCommentSuccessTitle, + text: strings.trainerReportOverview.reportCommentSuccess, + type: 'success', + }) }) } @@ -332,10 +352,10 @@ const EntryInput: React.FC = ({ } /> )} - + {showComment && ( - + )} diff --git a/packages/frontend/src/components/report-page-footer.tsx b/packages/frontend/src/components/report-page-footer.tsx index 2064fc3..842996a 100644 --- a/packages/frontend/src/components/report-page-footer.tsx +++ b/packages/frontend/src/components/report-page-footer.tsx @@ -8,10 +8,11 @@ import CommentSection from './comment-section' import { TextArea } from './text-area' import Total from './total' import { useReportHelper } from '../helper/report-helper' +import { useToastContext } from '../hooks/use-toast-context' interface ReportPageFooterProps { report: Pick & { - comments: (Pick & { + comments: (Pick & { user: Pick })[] days: (Pick & { @@ -21,11 +22,19 @@ interface ReportPageFooterProps { user: Pick disabled: boolean updateReport: (values: Partial) => Promise + updateMessage?: (message: string, commentId: string) => void } -const ReportPageFooter: React.FunctionComponent = ({ disabled, report, updateReport, user }) => { +const ReportPageFooter: React.FunctionComponent = ({ + disabled, + report, + updateReport, + user, + updateMessage, +}) => { const [createCommentOnReportMutation] = useCreateCommentOnReportMutation() + const { addToast } = useToastContext() const { getTotalMinutes } = useReportHelper() const updateRemarks = (event: React.FormEvent) => { @@ -59,11 +68,19 @@ const ReportPageFooter: React.FunctionComponent = ({ disa id: 'null', text, user, + published: false, }, ], }, }, }, + }).then(() => { + addToast({ + icon: 'Comment', + title: strings.trainerReportOverview.reportCommentSuccessTitle, + text: strings.trainerReportOverview.reportCommentSuccess, + type: 'success', + }) }) } @@ -83,6 +100,7 @@ const ReportPageFooter: React.FunctionComponent = ({ disa comments={report.comments} onSubmit={commentOnReport} displayTextInput={report.status === ReportStatus.Reopened} + updateMessage={updateMessage} /> diff --git a/packages/frontend/src/graphql/index.tsx b/packages/frontend/src/graphql/index.tsx index 379097f..199ce7e 100644 --- a/packages/frontend/src/graphql/index.tsx +++ b/packages/frontend/src/graphql/index.tsx @@ -37,6 +37,7 @@ export type Comment = { __typename?: 'Comment'; createdAt: Scalars['String']['output']; id: Scalars['ID']['output']; + published: Scalars['Boolean']['output']; text?: Maybe; user: UserInterface; }; @@ -105,6 +106,12 @@ export enum DayStatusEnum { Work = 'work' } +export type DeleteCommentPayload = { + __typename?: 'DeleteCommentPayload'; + comment: Comment; + commentable: CommentableInterface; +}; + /** Autogenerated return type of DevSetUser */ export type DevSetUserPayload = { __typename?: 'DevSetUserPayload'; @@ -169,6 +176,12 @@ export type Mutation = { createTrainee?: Maybe; /** Creates Trainer. */ createTrainer?: Maybe; + /** Deletes a comment on a Day which is identified by the id argument. */ + deleteCommentOnDay: DeleteCommentPayload; + /** Deletes a comment on a Entry which is identified by the id argument. */ + deleteCommentOnEntry: DeleteCommentPayload; + /** Deletes a comment on a Report which is identified by the id argument. */ + deleteCommentOnReport: DeleteCommentPayload; /** Deletes an entry by the given ID. Only considers entries made by the current user. Returns the ID of the deleted entry. */ deleteEntry: MutateEntryPayload; /** Get Avatar Bucket Upload URL */ @@ -179,6 +192,8 @@ export type Mutation = { login?: Maybe; /** Marks User to be deleted */ markUserForDeletion?: Maybe; + /** Publishes all comments on a report which is identified by the id argument. */ + publishAllComments: PublishCommentsPayload; /** Unclaims a Trainee by the current Trainer */ unclaimTrainee?: Maybe; /** Unlink Alexa account */ @@ -187,6 +202,12 @@ export type Mutation = { unmarkUserForDeletion?: Maybe; /** Updates Admin. */ updateAdmin?: Maybe; + /** Updates a comment on a Day which is identified by the id argument. */ + updateCommentOnDay: UpdateCommentPayload; + /** Updates a comment on a Entry which is identified by the id argument. */ + updateCommentOnEntry: UpdateCommentPayload; + /** Updates a comment on a Report which is identified by the id argument. */ + updateCommentOnReport: UpdateCommentPayload; /** Updates the current trainee */ updateCurrentTrainee?: Maybe; /** Updates the current user */ @@ -261,6 +282,27 @@ export type MutationCreateTrainerArgs = { }; +export type MutationDeleteCommentOnDayArgs = { + commentId: Scalars['ID']['input']; + id: Scalars['ID']['input']; + traineeId: Scalars['ID']['input']; +}; + + +export type MutationDeleteCommentOnEntryArgs = { + commentId: Scalars['ID']['input']; + id: Scalars['ID']['input']; + traineeId: Scalars['ID']['input']; +}; + + +export type MutationDeleteCommentOnReportArgs = { + commentId: Scalars['ID']['input']; + id: Scalars['ID']['input']; + traineeId: Scalars['ID']['input']; +}; + + export type MutationDeleteEntryArgs = { id: Scalars['ID']['input']; }; @@ -287,6 +329,12 @@ export type MutationMarkUserForDeletionArgs = { }; +export type MutationPublishAllCommentsArgs = { + id: Scalars['ID']['input']; + traineeId: Scalars['ID']['input']; +}; + + export type MutationUnclaimTraineeArgs = { id: Scalars['ID']['input']; }; @@ -303,6 +351,30 @@ export type MutationUpdateAdminArgs = { }; +export type MutationUpdateCommentOnDayArgs = { + commentId: Scalars['ID']['input']; + id: Scalars['ID']['input']; + text: Scalars['String']['input']; + traineeId: Scalars['ID']['input']; +}; + + +export type MutationUpdateCommentOnEntryArgs = { + commentId: Scalars['ID']['input']; + id: Scalars['ID']['input']; + text: Scalars['String']['input']; + traineeId: Scalars['ID']['input']; +}; + + +export type MutationUpdateCommentOnReportArgs = { + commentId: Scalars['ID']['input']; + id: Scalars['ID']['input']; + text: Scalars['String']['input']; + traineeId: Scalars['ID']['input']; +}; + + export type MutationUpdateCurrentTraineeArgs = { input: UpdateCurrentTraineeInput; }; @@ -363,6 +435,11 @@ export type PrintPayload = { estimatedWaitingTime: Scalars['Int']['output']; }; +export type PublishCommentsPayload = { + __typename?: 'PublishCommentsPayload'; + report: Report; +}; + export type Query = { __typename?: 'Query'; /** Get all Admins */ @@ -509,6 +586,12 @@ export type UpdateAdminInput = { lastName?: InputMaybe; }; +export type UpdateCommentPayload = { + __typename?: 'UpdateCommentPayload'; + comment: Comment; + commentable: CommentableInterface; +}; + export type UpdateCurrentTraineeInput = { course?: InputMaybe; }; @@ -602,7 +685,7 @@ export type CreateCommentOnDayMutationVariables = Exact<{ }>; -export type CreateCommentOnDayMutation = { __typename?: 'Mutation', createCommentOnDay: { __typename?: 'CreateCommentPayload', commentable: { __typename?: 'Day', id: string, comments: Array<{ __typename?: 'Comment', id: string, text?: string | undefined, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }> } | { __typename?: 'Entry' } | { __typename?: 'Report' } } }; +export type CreateCommentOnDayMutation = { __typename?: 'Mutation', createCommentOnDay: { __typename?: 'CreateCommentPayload', commentable: { __typename?: 'Day', id: string, comments: Array<{ __typename?: 'Comment', id: string, text?: string | undefined, published: boolean, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }> } | { __typename?: 'Entry' } | { __typename?: 'Report' } } }; export type CreateCommentOnEntryMutationVariables = Exact<{ id: Scalars['ID']['input']; @@ -611,7 +694,7 @@ export type CreateCommentOnEntryMutationVariables = Exact<{ }>; -export type CreateCommentOnEntryMutation = { __typename?: 'Mutation', createCommentOnEntry: { __typename?: 'CreateCommentPayload', commentable: { __typename?: 'Day' } | { __typename?: 'Entry', id: string, comments: Array<{ __typename?: 'Comment', id: string, text?: string | undefined, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }> } | { __typename?: 'Report' } } }; +export type CreateCommentOnEntryMutation = { __typename?: 'Mutation', createCommentOnEntry: { __typename?: 'CreateCommentPayload', commentable: { __typename?: 'Day' } | { __typename?: 'Entry', id: string, comments: Array<{ __typename?: 'Comment', id: string, text?: string | undefined, published: boolean, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }> } | { __typename?: 'Report' } } }; export type CreateCommentOnReportMutationVariables = Exact<{ id: Scalars['ID']['input']; @@ -620,7 +703,7 @@ export type CreateCommentOnReportMutationVariables = Exact<{ }>; -export type CreateCommentOnReportMutation = { __typename?: 'Mutation', createCommentOnReport: { __typename?: 'CreateCommentPayload', commentable: { __typename?: 'Day' } | { __typename?: 'Entry' } | { __typename?: 'Report', id: string, comments: Array<{ __typename?: 'Comment', id: string, text?: string | undefined, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }> } } }; +export type CreateCommentOnReportMutation = { __typename?: 'Mutation', createCommentOnReport: { __typename?: 'CreateCommentPayload', commentable: { __typename?: 'Day' } | { __typename?: 'Entry' } | { __typename?: 'Report', id: string, comments: Array<{ __typename?: 'Comment', id: string, text?: string | undefined, published: boolean, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }> } } }; export type CreateEntryMutationVariables = Exact<{ dayId: Scalars['String']['input']; @@ -671,6 +754,33 @@ export type DebugSetUsertypeMutationVariables = Exact<{ export type DebugSetUsertypeMutation = { __typename?: 'Mutation', _devsetusertype: { __typename?: 'DevSetUserPayload', user?: { __typename: 'Admin', id: string } | { __typename: 'Trainee', id: string } | { __typename: 'Trainer', id: string } | undefined } }; +export type DeleteCommentOnDayMutationVariables = Exact<{ + id: Scalars['ID']['input']; + traineeId: Scalars['ID']['input']; + commentId: Scalars['ID']['input']; +}>; + + +export type DeleteCommentOnDayMutation = { __typename?: 'Mutation', deleteCommentOnDay: { __typename?: 'DeleteCommentPayload', commentable: { __typename?: 'Day', id: string, comments: Array<{ __typename?: 'Comment', id: string, text?: string | undefined, published: boolean, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }> } | { __typename?: 'Entry' } | { __typename?: 'Report' } } }; + +export type DeleteCommentOnEntryMutationVariables = Exact<{ + id: Scalars['ID']['input']; + traineeId: Scalars['ID']['input']; + commentId: Scalars['ID']['input']; +}>; + + +export type DeleteCommentOnEntryMutation = { __typename?: 'Mutation', deleteCommentOnEntry: { __typename?: 'DeleteCommentPayload', commentable: { __typename?: 'Day' } | { __typename?: 'Entry', id: string, comments: Array<{ __typename?: 'Comment', id: string, text?: string | undefined, published: boolean, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }> } | { __typename?: 'Report' } } }; + +export type DeleteCommentOnReportMutationVariables = Exact<{ + id: Scalars['ID']['input']; + traineeId: Scalars['ID']['input']; + commentId: Scalars['ID']['input']; +}>; + + +export type DeleteCommentOnReportMutation = { __typename?: 'Mutation', deleteCommentOnReport: { __typename?: 'DeleteCommentPayload', commentable: { __typename?: 'Day' } | { __typename?: 'Entry' } | { __typename?: 'Report', id: string, comments: Array<{ __typename?: 'Comment', id: string, text?: string | undefined, published: boolean, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }> } } }; + export type DeleteEntryMutationVariables = Exact<{ id: Scalars['ID']['input']; }>; @@ -700,6 +810,14 @@ export type MarkUserForDeleteMutationVariables = Exact<{ export type MarkUserForDeleteMutation = { __typename?: 'Mutation', markUserForDeletion?: { __typename?: 'Admin', deleteAt?: string | undefined, id: string } | { __typename?: 'Trainee', deleteAt?: string | undefined, id: string } | { __typename?: 'Trainer', deleteAt?: string | undefined, id: string } | undefined }; +export type PublishAllCommentsMutationVariables = Exact<{ + id: Scalars['ID']['input']; + traineeId: Scalars['ID']['input']; +}>; + + +export type PublishAllCommentsMutation = { __typename?: 'Mutation', publishAllComments: { __typename?: 'PublishCommentsPayload', report: { __typename?: 'Report', id: string, comments: Array<{ __typename?: 'Comment', id: string, text?: string | undefined, published: boolean, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }> } } }; + export type SignatureSettingsUpdateSignatureMutationVariables = Exact<{ signature?: InputMaybe; }>; @@ -741,6 +859,36 @@ export type UpdateAdminMutationVariables = Exact<{ export type UpdateAdminMutation = { __typename?: 'Mutation', updateAdmin?: { __typename?: 'Admin', id: string, firstName: string, lastName: string, email: string, type: UserTypeEnum } | undefined }; +export type UpdateCommentOnDayMutationVariables = Exact<{ + id: Scalars['ID']['input']; + text: Scalars['String']['input']; + traineeId: Scalars['ID']['input']; + commentId: Scalars['ID']['input']; +}>; + + +export type UpdateCommentOnDayMutation = { __typename?: 'Mutation', updateCommentOnDay: { __typename?: 'UpdateCommentPayload', commentable: { __typename?: 'Day', id: string, comments: Array<{ __typename?: 'Comment', id: string, text?: string | undefined, published: boolean, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }> } | { __typename?: 'Entry' } | { __typename?: 'Report' } } }; + +export type UpdateCommentOnEntryMutationVariables = Exact<{ + id: Scalars['ID']['input']; + text: Scalars['String']['input']; + traineeId: Scalars['ID']['input']; + commentId: Scalars['ID']['input']; +}>; + + +export type UpdateCommentOnEntryMutation = { __typename?: 'Mutation', updateCommentOnEntry: { __typename?: 'UpdateCommentPayload', commentable: { __typename?: 'Day' } | { __typename?: 'Entry', id: string, comments: Array<{ __typename?: 'Comment', id: string, text?: string | undefined, published: boolean, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }> } | { __typename?: 'Report' } } }; + +export type UpdateCommentOnReportMutationVariables = Exact<{ + id: Scalars['ID']['input']; + text: Scalars['String']['input']; + traineeId: Scalars['ID']['input']; + commentId: Scalars['ID']['input']; +}>; + + +export type UpdateCommentOnReportMutation = { __typename?: 'Mutation', updateCommentOnReport: { __typename?: 'UpdateCommentPayload', commentable: { __typename?: 'Day' } | { __typename?: 'Entry' } | { __typename?: 'Report', id: string, comments: Array<{ __typename?: 'Comment', id: string, text?: string | undefined, published: boolean, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }> } } }; + export type UpdateEntryOrderMutationVariables = Exact<{ entryId: Scalars['ID']['input']; dayId: Scalars['ID']['input']; @@ -845,7 +993,7 @@ export type DashboardPageDataQueryVariables = Exact<{ }>; -export type DashboardPageDataQuery = { __typename?: 'Query', currentUser?: { __typename?: 'Admin', id: string, theme?: string | undefined } | { __typename?: 'Trainee', id: string, theme?: string | undefined } | { __typename?: 'Trainer', id: string, theme?: string | undefined } | undefined, reports: Array<{ __typename: 'Report', id: string, week: number, year: number, status: ReportStatus, department?: string | undefined, days: Array<{ __typename?: 'Day', status?: DayStatusEnum | undefined, entries: Array<{ __typename?: 'Entry', id: string, time: number }> }> } | undefined>, reportForYearAndWeek?: { __typename?: 'Report', id: string, status: ReportStatus, days: Array<{ __typename?: 'Day', status?: DayStatusEnum | undefined, date: string, id: string, entries: Array<{ __typename?: 'Entry', id: string, text: string, time: number, orderId: number, comments: Array<{ __typename?: 'Comment', id: string, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }> }>, comments: Array<{ __typename?: 'Comment', id: string, text?: string | undefined, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }> }> } | undefined }; +export type DashboardPageDataQuery = { __typename?: 'Query', currentUser?: { __typename?: 'Admin', id: string, theme?: string | undefined } | { __typename?: 'Trainee', id: string, theme?: string | undefined } | { __typename?: 'Trainer', id: string, theme?: string | undefined } | undefined, reports: Array<{ __typename: 'Report', id: string, week: number, year: number, status: ReportStatus, department?: string | undefined, days: Array<{ __typename?: 'Day', status?: DayStatusEnum | undefined, entries: Array<{ __typename?: 'Entry', id: string, time: number }> }> } | undefined>, reportForYearAndWeek?: { __typename?: 'Report', id: string, status: ReportStatus, days: Array<{ __typename?: 'Day', status?: DayStatusEnum | undefined, date: string, id: string, entries: Array<{ __typename?: 'Entry', id: string, text: string, time: number, orderId: number, comments: Array<{ __typename?: 'Comment', id: string, published: boolean, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }> }>, comments: Array<{ __typename?: 'Comment', id: string, text?: string | undefined, published: boolean, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }> }> } | undefined }; export type DayInputDataQueryVariables = Exact<{ [key: string]: never; }>; @@ -887,7 +1035,7 @@ export type ReportPageDataQueryVariables = Exact<{ }>; -export type ReportPageDataQuery = { __typename?: 'Query', currentUser?: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', startOfToolUsage?: string | undefined, endOfToolUsage?: string | undefined, id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } | undefined, reportForYearAndWeek?: { __typename?: 'Report', id: string, week: number, year: number, summary?: string | undefined, department?: string | undefined, status: ReportStatus, previousReportLink?: string | undefined, nextReportLink?: string | undefined, comments: Array<{ __typename?: 'Comment', id: string, text?: string | undefined, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }>, days: Array<{ __typename?: 'Day', status?: DayStatusEnum | undefined, date: string, id: string, comments: Array<{ __typename?: 'Comment', id: string, text?: string | undefined, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }>, entries: Array<{ __typename?: 'Entry', id: string, text: string, time: number, orderId: number, comments: Array<{ __typename?: 'Comment', id: string, text?: string | undefined, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }> }> }> } | undefined }; +export type ReportPageDataQuery = { __typename?: 'Query', currentUser?: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', startOfToolUsage?: string | undefined, endOfToolUsage?: string | undefined, id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } | undefined, reportForYearAndWeek?: { __typename?: 'Report', id: string, week: number, year: number, summary?: string | undefined, department?: string | undefined, status: ReportStatus, previousReportLink?: string | undefined, nextReportLink?: string | undefined, comments: Array<{ __typename?: 'Comment', id: string, text?: string | undefined, published: boolean, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }>, days: Array<{ __typename?: 'Day', status?: DayStatusEnum | undefined, date: string, id: string, comments: Array<{ __typename?: 'Comment', id: string, text?: string | undefined, published: boolean, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }>, entries: Array<{ __typename?: 'Entry', id: string, text: string, time: number, orderId: number, comments: Array<{ __typename?: 'Comment', id: string, text?: string | undefined, published: boolean, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }> }> }> } | undefined }; export type ReportReviewPageDataQueryVariables = Exact<{ year: Scalars['Int']['input']; @@ -896,7 +1044,7 @@ export type ReportReviewPageDataQueryVariables = Exact<{ }>; -export type ReportReviewPageDataQuery = { __typename?: 'Query', currentUser?: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } | undefined, reportForTrainee?: { __typename?: 'Report', id: string, week: number, year: number, summary?: string | undefined, department?: string | undefined, status: ReportStatus, comments: Array<{ __typename?: 'Comment', id: string, text?: string | undefined, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }>, days: Array<{ __typename?: 'Day', status?: DayStatusEnum | undefined, date: string, id: string, entries: Array<{ __typename?: 'Entry', id: string, text: string, time: number, orderId: number, comments: Array<{ __typename?: 'Comment', id: string, text?: string | undefined, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }> }>, comments: Array<{ __typename?: 'Comment', id: string, text?: string | undefined, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }> }> } | undefined }; +export type ReportReviewPageDataQuery = { __typename?: 'Query', currentUser?: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } | undefined, reportForTrainee?: { __typename?: 'Report', id: string, week: number, year: number, summary?: string | undefined, department?: string | undefined, status: ReportStatus, comments: Array<{ __typename?: 'Comment', id: string, text?: string | undefined, published: boolean, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }>, days: Array<{ __typename?: 'Day', status?: DayStatusEnum | undefined, date: string, id: string, entries: Array<{ __typename?: 'Entry', id: string, text: string, time: number, orderId: number, comments: Array<{ __typename?: 'Comment', id: string, text?: string | undefined, published: boolean, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }> }>, comments: Array<{ __typename?: 'Comment', id: string, text?: string | undefined, published: boolean, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }> }> } | undefined }; export type SettingsPageDataQueryVariables = Exact<{ [key: string]: never; }>; @@ -1015,6 +1163,7 @@ export const CreateCommentOnDayDocument = gql` firstName lastName } + published } } } @@ -1040,6 +1189,7 @@ export const CreateCommentOnEntryDocument = gql` firstName lastName } + published } } } @@ -1065,6 +1215,7 @@ export const CreateCommentOnReportDocument = gql` firstName lastName } + published } } } @@ -1193,6 +1344,84 @@ export function useDebugSetUsertypeMutation(baseOptions?: Apollo.MutationHookOpt return Apollo.useMutation(DebugSetUsertypeDocument, options); } export type DebugSetUsertypeMutationHookResult = ReturnType; +export const DeleteCommentOnDayDocument = gql` + mutation deleteCommentOnDay($id: ID!, $traineeId: ID!, $commentId: ID!) { + deleteCommentOnDay(id: $id, traineeId: $traineeId, commentId: $commentId) { + commentable { + ... on Day { + id + comments { + id + text + user { + id + firstName + lastName + } + published + } + } + } + } +} + `; +export function useDeleteCommentOnDayMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(DeleteCommentOnDayDocument, options); + } +export type DeleteCommentOnDayMutationHookResult = ReturnType; +export const DeleteCommentOnEntryDocument = gql` + mutation deleteCommentOnEntry($id: ID!, $traineeId: ID!, $commentId: ID!) { + deleteCommentOnEntry(id: $id, traineeId: $traineeId, commentId: $commentId) { + commentable { + ... on Entry { + id + comments { + id + text + user { + id + firstName + lastName + } + published + } + } + } + } +} + `; +export function useDeleteCommentOnEntryMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(DeleteCommentOnEntryDocument, options); + } +export type DeleteCommentOnEntryMutationHookResult = ReturnType; +export const DeleteCommentOnReportDocument = gql` + mutation deleteCommentOnReport($id: ID!, $traineeId: ID!, $commentId: ID!) { + deleteCommentOnReport(id: $id, traineeId: $traineeId, commentId: $commentId) { + commentable { + ... on Report { + id + comments { + id + text + user { + id + firstName + lastName + } + published + } + } + } + } +} + `; +export function useDeleteCommentOnReportMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(DeleteCommentOnReportDocument, options); + } +export type DeleteCommentOnReportMutationHookResult = ReturnType; export const DeleteEntryDocument = gql` mutation deleteEntry($id: ID!) { deleteEntry(id: $id) { @@ -1259,6 +1488,30 @@ export function useMarkUserForDeleteMutation(baseOptions?: Apollo.MutationHookOp return Apollo.useMutation(MarkUserForDeleteDocument, options); } export type MarkUserForDeleteMutationHookResult = ReturnType; +export const PublishAllCommentsDocument = gql` + mutation publishAllComments($id: ID!, $traineeId: ID!) { + publishAllComments(id: $id, traineeId: $traineeId) { + report { + id + comments { + id + text + user { + id + firstName + lastName + } + published + } + } + } +} + `; +export function usePublishAllCommentsMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(PublishAllCommentsDocument, options); + } +export type PublishAllCommentsMutationHookResult = ReturnType; export const SignatureSettingsUpdateSignatureDocument = gql` mutation SignatureSettingsUpdateSignature($signature: String) { updateCurrentUser(input: {signature: $signature}) { @@ -1358,6 +1611,99 @@ export function useUpdateAdminMutation(baseOptions?: Apollo.MutationHookOptions< return Apollo.useMutation(UpdateAdminDocument, options); } export type UpdateAdminMutationHookResult = ReturnType; +export const UpdateCommentOnDayDocument = gql` + mutation updateCommentOnDay($id: ID!, $text: String!, $traineeId: ID!, $commentId: ID!) { + updateCommentOnDay( + id: $id + text: $text + traineeId: $traineeId + commentId: $commentId + ) { + commentable { + ... on Day { + id + comments { + id + text + user { + id + firstName + lastName + } + published + } + } + } + } +} + `; +export function useUpdateCommentOnDayMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(UpdateCommentOnDayDocument, options); + } +export type UpdateCommentOnDayMutationHookResult = ReturnType; +export const UpdateCommentOnEntryDocument = gql` + mutation updateCommentOnEntry($id: ID!, $text: String!, $traineeId: ID!, $commentId: ID!) { + updateCommentOnEntry( + id: $id + text: $text + traineeId: $traineeId + commentId: $commentId + ) { + commentable { + ... on Entry { + id + comments { + id + text + user { + id + firstName + lastName + } + published + } + } + } + } +} + `; +export function useUpdateCommentOnEntryMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(UpdateCommentOnEntryDocument, options); + } +export type UpdateCommentOnEntryMutationHookResult = ReturnType; +export const UpdateCommentOnReportDocument = gql` + mutation updateCommentOnReport($id: ID!, $text: String!, $traineeId: ID!, $commentId: ID!) { + updateCommentOnReport( + id: $id + text: $text + traineeId: $traineeId + commentId: $commentId + ) { + commentable { + ... on Report { + id + comments { + id + text + user { + id + firstName + lastName + } + published + } + } + } + } +} + `; +export function useUpdateCommentOnReportMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(UpdateCommentOnReportDocument, options); + } +export type UpdateCommentOnReportMutationHookResult = ReturnType; export const UpdateEntryOrderDocument = gql` mutation updateEntryOrder($entryId: ID!, $dayId: ID!, $orderId: Int!) { updateEntryOrder(entryId: $entryId, dayId: $dayId, orderId: $orderId) { @@ -1785,6 +2131,7 @@ export const DashboardPageDataDocument = gql` firstName lastName } + published } } comments { @@ -1795,6 +2142,7 @@ export const DashboardPageDataDocument = gql` firstName lastName } + published } } } @@ -2023,6 +2371,7 @@ export const ReportPageDataDocument = gql` firstName lastName } + published } days { status @@ -2036,6 +2385,7 @@ export const ReportPageDataDocument = gql` firstName lastName } + published } entries { id @@ -2050,6 +2400,7 @@ export const ReportPageDataDocument = gql` firstName lastName } + published } } } @@ -2093,6 +2444,7 @@ export const ReportReviewPageDataDocument = gql` firstName lastName } + published } days { status @@ -2111,6 +2463,7 @@ export const ReportReviewPageDataDocument = gql` firstName lastName } + published } } comments { @@ -2121,6 +2474,7 @@ export const ReportReviewPageDataDocument = gql` firstName lastName } + published } } } diff --git a/packages/frontend/src/graphql/mutations/create-comment-on-day.gql b/packages/frontend/src/graphql/mutations/create-comment-on-day.gql index 14fcecc..d012876 100644 --- a/packages/frontend/src/graphql/mutations/create-comment-on-day.gql +++ b/packages/frontend/src/graphql/mutations/create-comment-on-day.gql @@ -11,6 +11,7 @@ mutation createCommentOnDay($id: ID!, $text: String!, $traineeId: ID!) { firstName lastName } + published } } } diff --git a/packages/frontend/src/graphql/mutations/create-comment-on-entry.gql b/packages/frontend/src/graphql/mutations/create-comment-on-entry.gql index 9cb92ce..d09bb37 100644 --- a/packages/frontend/src/graphql/mutations/create-comment-on-entry.gql +++ b/packages/frontend/src/graphql/mutations/create-comment-on-entry.gql @@ -11,6 +11,7 @@ mutation createCommentOnEntry($id: ID!, $text: String!, $traineeId: ID!) { firstName lastName } + published } } } diff --git a/packages/frontend/src/graphql/mutations/create-comment-on-report.gql b/packages/frontend/src/graphql/mutations/create-comment-on-report.gql index 02796c7..e682da4 100644 --- a/packages/frontend/src/graphql/mutations/create-comment-on-report.gql +++ b/packages/frontend/src/graphql/mutations/create-comment-on-report.gql @@ -11,6 +11,7 @@ mutation createCommentOnReport($id: ID!, $text: String!, $traineeId: ID!) { firstName lastName } + published } } } diff --git a/packages/frontend/src/graphql/mutations/delete-comment-on-day.gql b/packages/frontend/src/graphql/mutations/delete-comment-on-day.gql new file mode 100644 index 0000000..1359581 --- /dev/null +++ b/packages/frontend/src/graphql/mutations/delete-comment-on-day.gql @@ -0,0 +1,19 @@ +mutation deleteCommentOnDay($id: ID!, $traineeId: ID!, $commentId: ID!) { + deleteCommentOnDay(id: $id, traineeId: $traineeId, commentId: $commentId) { + commentable { + ... on Day { + id + comments { + id + text + user { + id + firstName + lastName + } + published + } + } + } + } +} diff --git a/packages/frontend/src/graphql/mutations/delete-comment-on-entry.gql b/packages/frontend/src/graphql/mutations/delete-comment-on-entry.gql new file mode 100644 index 0000000..cc62ac9 --- /dev/null +++ b/packages/frontend/src/graphql/mutations/delete-comment-on-entry.gql @@ -0,0 +1,19 @@ +mutation deleteCommentOnEntry($id: ID!, $traineeId: ID!, $commentId: ID!) { + deleteCommentOnEntry(id: $id, traineeId: $traineeId, commentId: $commentId) { + commentable { + ... on Entry { + id + comments { + id + text + user { + id + firstName + lastName + } + published + } + } + } + } +} diff --git a/packages/frontend/src/graphql/mutations/delete-comment-on-report.gql b/packages/frontend/src/graphql/mutations/delete-comment-on-report.gql new file mode 100644 index 0000000..22caeea --- /dev/null +++ b/packages/frontend/src/graphql/mutations/delete-comment-on-report.gql @@ -0,0 +1,19 @@ +mutation deleteCommentOnReport($id: ID!, $traineeId: ID!, $commentId: ID!) { + deleteCommentOnReport(id: $id, traineeId: $traineeId, commentId: $commentId) { + commentable { + ... on Report { + id + comments { + id + text + user { + id + firstName + lastName + } + published + } + } + } + } +} diff --git a/packages/frontend/src/graphql/mutations/publish-all-comments.gql b/packages/frontend/src/graphql/mutations/publish-all-comments.gql new file mode 100644 index 0000000..ab70f3d --- /dev/null +++ b/packages/frontend/src/graphql/mutations/publish-all-comments.gql @@ -0,0 +1,17 @@ +mutation publishAllComments($id: ID!, $traineeId: ID!) { + publishAllComments(id: $id, traineeId: $traineeId) { + report { + id + comments { + id + text + user { + id + firstName + lastName + } + published + } + } + } +} diff --git a/packages/frontend/src/graphql/mutations/update-comment-on-day.gql b/packages/frontend/src/graphql/mutations/update-comment-on-day.gql new file mode 100644 index 0000000..e0f41fa --- /dev/null +++ b/packages/frontend/src/graphql/mutations/update-comment-on-day.gql @@ -0,0 +1,19 @@ +mutation updateCommentOnDay($id: ID!, $text: String!, $traineeId: ID!, $commentId: ID!) { + updateCommentOnDay(id: $id, text: $text, traineeId: $traineeId, commentId: $commentId) { + commentable { + ... on Day { + id + comments { + id + text + user { + id + firstName + lastName + } + published + } + } + } + } +} diff --git a/packages/frontend/src/graphql/mutations/update-comment-on-entry.gql b/packages/frontend/src/graphql/mutations/update-comment-on-entry.gql new file mode 100644 index 0000000..bbbb94d --- /dev/null +++ b/packages/frontend/src/graphql/mutations/update-comment-on-entry.gql @@ -0,0 +1,19 @@ +mutation updateCommentOnEntry($id: ID!, $text: String!, $traineeId: ID!, $commentId: ID!) { + updateCommentOnEntry(id: $id, text: $text, traineeId: $traineeId, commentId: $commentId) { + commentable { + ... on Entry { + id + comments { + id + text + user { + id + firstName + lastName + } + published + } + } + } + } +} diff --git a/packages/frontend/src/graphql/mutations/update-comment-on-report.gql b/packages/frontend/src/graphql/mutations/update-comment-on-report.gql new file mode 100644 index 0000000..51b4bbe --- /dev/null +++ b/packages/frontend/src/graphql/mutations/update-comment-on-report.gql @@ -0,0 +1,19 @@ +mutation updateCommentOnReport($id: ID!, $text: String!, $traineeId: ID!, $commentId: ID!) { + updateCommentOnReport(id: $id, text: $text, traineeId: $traineeId, commentId: $commentId) { + commentable { + ... on Report { + id + comments { + id + text + user { + id + firstName + lastName + } + published + } + } + } + } +} diff --git a/packages/frontend/src/graphql/queries/dashboard-page-data.gql b/packages/frontend/src/graphql/queries/dashboard-page-data.gql index 0e6cb12..9098e89 100644 --- a/packages/frontend/src/graphql/queries/dashboard-page-data.gql +++ b/packages/frontend/src/graphql/queries/dashboard-page-data.gql @@ -37,6 +37,7 @@ query DashboardPageData($currentYear: Int!, $currentWeek: Int!) { firstName lastName } + published } } comments { @@ -47,6 +48,7 @@ query DashboardPageData($currentYear: Int!, $currentWeek: Int!) { firstName lastName } + published } } } diff --git a/packages/frontend/src/graphql/queries/report-page-data.gql b/packages/frontend/src/graphql/queries/report-page-data.gql index 0c195b1..8ac3dfb 100644 --- a/packages/frontend/src/graphql/queries/report-page-data.gql +++ b/packages/frontend/src/graphql/queries/report-page-data.gql @@ -25,6 +25,7 @@ query ReportPageData($year: Int!, $week: Int!) { firstName lastName } + published } days { status @@ -38,6 +39,7 @@ query ReportPageData($year: Int!, $week: Int!) { firstName lastName } + published } entries { id @@ -52,6 +54,7 @@ query ReportPageData($year: Int!, $week: Int!) { firstName lastName } + published } } } diff --git a/packages/frontend/src/graphql/queries/report-review-page-data.gql b/packages/frontend/src/graphql/queries/report-review-page-data.gql index 5a263f4..5b2f2df 100644 --- a/packages/frontend/src/graphql/queries/report-review-page-data.gql +++ b/packages/frontend/src/graphql/queries/report-review-page-data.gql @@ -19,6 +19,7 @@ query reportReviewPageData($year: Int!, $week: Int!, $trainee: ID!) { firstName lastName } + published } days { status @@ -37,6 +38,7 @@ query reportReviewPageData($year: Int!, $week: Int!, $trainee: ID!) { firstName lastName } + published } } comments { @@ -47,6 +49,7 @@ query reportReviewPageData($year: Int!, $week: Int!, $trainee: ID!) { firstName lastName } + published } } } diff --git a/packages/frontend/src/pages/report-page.tsx b/packages/frontend/src/pages/report-page.tsx index 9c97598..5fa15f2 100644 --- a/packages/frontend/src/pages/report-page.tsx +++ b/packages/frontend/src/pages/report-page.tsx @@ -12,11 +12,22 @@ import ReportPageFooter from '../components/report-page-footer' import ReportPageHeader from '../components/report-page-header' import { EntryOrderProvider } from '../context/entry-order' import { + Comment, + Day, DayStatusEnum, + Entry, Report, ReportPageDataQueryVariables, ReportStatus, + useDeleteCommentOnDayMutation, + useDeleteCommentOnEntryMutation, + useDeleteCommentOnReportMutation, + usePublishAllCommentsMutation, useReportPageDataQuery, + UserInterface, + useUpdateCommentOnDayMutation, + useUpdateCommentOnEntryMutation, + useUpdateCommentOnReportMutation, useUpdateReportMutation, } from '../graphql' import { useFetchPdf } from '../hooks/use-fetch-pdf' @@ -37,7 +48,9 @@ const ReportPage: React.FunctionComponent = () => { } const { loading, data } = useReportPageDataQuery({ variables }) + const report = data?.reportForYearAndWeek + const currentUser = data?.currentUser const [updateReportMutation] = useUpdateReportMutation() @@ -45,6 +58,16 @@ const ReportPage: React.FunctionComponent = () => { const [fetchPdf, pdfLoading] = useFetchPdf() + const [updateCommentOnReportMutation] = useUpdateCommentOnReportMutation() + const [updateCommentOnDayMutation] = useUpdateCommentOnDayMutation() + const [updateCommentOnEntryMutation] = useUpdateCommentOnEntryMutation() + + const [deleteCommentOnReportMutation] = useDeleteCommentOnReportMutation() + const [deleteCommentOnDayMutation] = useDeleteCommentOnDayMutation() + const [deleteCommentOnEntryMutation] = useDeleteCommentOnEntryMutation() + + const [publishAllCommentsMutation] = usePublishAllCommentsMutation() + const [showHandoverModal, setShowHandoverModal] = React.useState(false) const [showUnarchiveModal, setShowUnarchiveModal] = React.useState(false) @@ -96,13 +119,122 @@ const ReportPage: React.FunctionComponent = () => { }) } + function updateReportComment(text: string, commentId: string) { + if (!data) { + return + } + + const { currentUser } = data + if (!report || !currentUser || currentUser.__typename !== 'Trainee') { + return + } + if (text !== '') { + void updateCommentOnReportMutation({ + variables: { + id: report.id, + text, + traineeId: currentUser.id, + commentId, + }, + }) + } else { + void deleteCommentOnReportMutation({ + variables: { + id: report.id, + traineeId: currentUser.id, + commentId, + }, + }) + } + } + + function updateDayComment( + day: Pick & { + comments: (Pick & { + user: Pick + })[] + }, + text: string, + commentId: string + ) { + if (!data) { + return + } + + const { currentUser } = data + if (!currentUser || currentUser.__typename !== 'Trainee') { + return + } + if (text !== '') { + void updateCommentOnDayMutation({ + variables: { + id: day.id, + text, + traineeId: currentUser.id, + commentId, + }, + }) + } else { + void deleteCommentOnDayMutation({ + variables: { + id: day.id, + traineeId: currentUser.id, + commentId, + }, + }) + } + } + + function updateEntryComment( + entry: Pick & { + comments: (Pick & { + user: Pick + })[] + }, + text: string, + commentId: string + ) { + if (!data) { + return + } + + const { currentUser } = data + if (!currentUser || currentUser.__typename !== 'Trainee') { + return + } + if (text !== '') { + void updateCommentOnEntryMutation({ + variables: { + id: entry.id, + text, + traineeId: currentUser.id, + commentId, + }, + }) + } else { + void deleteCommentOnEntryMutation({ + variables: { + id: entry.id, + traineeId: currentUser.id, + commentId, + }, + }) + } + } + const handoverReport = () => { - void updateReport({ status: ReportStatus.Review }) + void updateReport({ status: ReportStatus.Review }).then(() => { + if (!report || !currentUser) return + publishAllCommentsMutation({ variables: { id: report.id, traineeId: currentUser.id } }) + }) navigate('/') } const unarchiveReport = () => { - void updateReport({ status: ReportStatus.Reopened }) + void updateReport({ status: ReportStatus.Reopened }).then(() => { + if (!report || !currentUser) return + publishAllCommentsMutation({ variables: { id: report.id, traineeId: currentUser.id } }) + }) navigate('/') } @@ -121,12 +253,14 @@ const ReportPage: React.FunctionComponent = () => { - {report.days.map((day) => ( + {report?.days.map((day) => ( updateDayComment(day, msg, commentId)} + updateMessageEntry={(msg, commentId, entry) => updateEntryComment(entry, msg, commentId)} /> ))} @@ -138,6 +272,7 @@ const ReportPage: React.FunctionComponent = () => { disabled={reportArchived || reportReview} user={data.currentUser} updateReport={updateReport} + updateMessage={(msg, commentId) => updateReportComment(msg, commentId)} /> )} diff --git a/packages/frontend/src/pages/report-review-page.tsx b/packages/frontend/src/pages/report-review-page.tsx index a763e4b..f6ccc30 100644 --- a/packages/frontend/src/pages/report-review-page.tsx +++ b/packages/frontend/src/pages/report-review-page.tsx @@ -25,13 +25,21 @@ import Total from '../components/total' import { Comment, Day, + Entry, ReportReviewPageDataQueryVariables, ReportStatus, UpdateReportMutationVariables, useCreateCommentOnDayMutation, useCreateCommentOnReportMutation, + useDeleteCommentOnDayMutation, + useDeleteCommentOnEntryMutation, + useDeleteCommentOnReportMutation, + usePublishAllCommentsMutation, useReportReviewPageDataQuery, UserInterface, + useUpdateCommentOnDayMutation, + useUpdateCommentOnEntryMutation, + useUpdateCommentOnReportMutation, useUpdateReportReportReviewPageMutation, } from '../graphql' import DateHelper from '../helper/date-helper' @@ -61,6 +69,17 @@ const ReportReviewPage: React.FunctionComponent = () => { const [createCommentOnDayMutation] = useCreateCommentOnDayMutation() const [createCommentOnReportMutation] = useCreateCommentOnReportMutation() const [updateReportMutation] = useUpdateReportReportReviewPageMutation() + + const [updateCommentOnReportMutation] = useUpdateCommentOnReportMutation() + const [updateCommentOnDayMutation] = useUpdateCommentOnDayMutation() + const [updateCommentOnEntryMutation] = useUpdateCommentOnEntryMutation() + + const [deleteCommentOnReportMutation] = useDeleteCommentOnReportMutation() + const [deleteCommentOnDayMutation] = useDeleteCommentOnDayMutation() + const [deleteCommentOnEntryMutation] = useDeleteCommentOnEntryMutation() + + const [publishAllCommentsMutation] = usePublishAllCommentsMutation() + const { addToast } = useToastContext() const [state, setState] = React.useState({ @@ -83,27 +102,37 @@ const ReportReviewPage: React.FunctionComponent = () => { } const handBackReport = () => { - updateReport({ status: ReportStatus.Reopened }).then(() => { - addToast({ - icon: 'Report', - title: strings.trainerReportOverview.reportDeclinedSuccessTitle, - text: strings.trainerReportOverview.reportDeclinedSuccess, - type: 'success', + updateReport({ status: ReportStatus.Reopened }) + .then(() => { + if (!data?.reportForTrainee) return + publishAllCommentsMutation({ variables: { id: data?.reportForTrainee.id, traineeId: variables.trainee } }) + }) + .then(() => { + addToast({ + icon: 'Report', + title: strings.trainerReportOverview.reportDeclinedSuccessTitle, + text: strings.trainerReportOverview.reportDeclinedSuccess, + type: 'success', + }) + navigate('/') }) - navigate('/') - }) } const archiveReport = () => { - updateReport({ status: ReportStatus.Archived }).then(() => { - addToast({ - icon: 'Report', - title: strings.trainerReportOverview.reportToArchiveSuccessTitle, - text: strings.trainerReportOverview.reportToArchiveSuccess, - type: 'success', + updateReport({ status: ReportStatus.Archived }) + .then(() => { + if (!data?.reportForTrainee) return + publishAllCommentsMutation({ variables: { id: data?.reportForTrainee.id, traineeId: variables.trainee } }) + }) + .then(() => { + addToast({ + icon: 'Report', + title: strings.trainerReportOverview.reportToArchiveSuccessTitle, + text: strings.trainerReportOverview.reportToArchiveSuccess, + type: 'success', + }) + navigate('/') }) - navigate('/') - }) } const updateReport = (values: Partial) => { @@ -147,6 +176,7 @@ const ReportReviewPage: React.FunctionComponent = () => { id: '', text, user: currentUser, + published: false, }, ], }, @@ -165,7 +195,7 @@ const ReportReviewPage: React.FunctionComponent = () => { const commentOnDay = ( day: Pick & { - comments: (Pick & { + comments: (Pick & { user: Pick })[] } @@ -194,6 +224,7 @@ const ReportReviewPage: React.FunctionComponent = () => { id: '', text, user: data?.currentUser, + published: false, }, ], }, @@ -209,6 +240,104 @@ const ReportReviewPage: React.FunctionComponent = () => { }) } + function updateReportComment(text: string, commentId: string) { + if (!data) { + return + } + + const { reportForTrainee, currentUser } = data + if (!reportForTrainee || !currentUser) { + return + } + if (text !== '') { + void updateCommentOnReportMutation({ + variables: { + id: reportForTrainee.id, + text, + traineeId: variables.trainee, + commentId, + }, + }) + } else { + void deleteCommentOnReportMutation({ + variables: { + id: reportForTrainee.id, + traineeId: variables.trainee, + commentId, + }, + }) + } + } + + function updateDayComment( + day: Pick & { + comments: (Pick & { + user: Pick + })[] + }, + text: string, + commentId: string + ) { + if (!data?.currentUser) { + return + } + if (text !== '') { + void updateCommentOnDayMutation({ + variables: { + id: day.id, + text, + traineeId: variables.trainee, + commentId, + }, + }) + } else { + void deleteCommentOnDayMutation({ + variables: { + id: day.id, + traineeId: variables.trainee, + commentId, + }, + }) + } + } + + function updateEntryComment( + entry: Pick & { + comments: (Pick & { + user: Pick + })[] + }, + text: string, + commentId: string + ) { + if (!data) { + return + } + + const { currentUser: user } = data + if (!user) { + return + } + if (text !== '') { + void updateCommentOnEntryMutation({ + variables: { + id: entry.id, + text, + traineeId: variables.trainee, + commentId, + }, + }) + } else { + void deleteCommentOnEntryMutation({ + variables: { + id: entry.id, + traineeId: variables.trainee, + commentId, + }, + }) + } + } + const getHeading = (day: Pick): string => { return DateHelper.format(Date.parse(day.date), 'EEEE') } @@ -265,6 +394,7 @@ const ReportReviewPage: React.FunctionComponent = () => { disabled={true} reportStatus={report.status} trainee={{ id: variables.trainee }} + updateMessage={(msg, commentId) => updateEntryComment(entry, msg, commentId)} /> ))} @@ -277,6 +407,7 @@ const ReportReviewPage: React.FunctionComponent = () => { comments={day.comments} onSubmit={commentOnDay(day)} displayTextInput={true} + updateMessage={(msg, commentId) => updateDayComment(day, msg, commentId)} /> ))} @@ -289,7 +420,13 @@ const ReportReviewPage: React.FunctionComponent = () => { {report.summary} - + updateReportComment(msg, commentId)} + />