Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/new attachments api #159

Closed
wants to merge 30 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
a7bfbf8
feat: use new attachment api
Aug 14, 2023
d49bf24
chore: improve error message
Aug 14, 2023
b24178d
refactor: use cmd extension
Aug 14, 2023
9872c61
feat: create command
Aug 14, 2023
16a4291
feat: upload file
Aug 16, 2023
49973d9
chore: use blob
Aug 16, 2023
9f4457d
chore: use fetch
Aug 16, 2023
dd7db44
chore: use http-client
Aug 16, 2023
4f978bb
chore: fix tests
Aug 17, 2023
3037545
chore: remove unneeded call
Aug 18, 2023
62d5949
feat: add state to control if the file has changed
Manumartin95 Aug 21, 2023
30dfb70
feat: remove unused url to file converter
Manumartin95 Aug 21, 2023
d123fd5
feat: add get attachment to attachment repository
Manumartin95 Aug 21, 2023
80f4d49
test: add attachment repository tests
Manumartin95 Aug 21, 2023
9df4a6e
feat: add get attachment to fake repository
Manumartin95 Aug 21, 2023
fb54ceb
refactor: remove unnecessary variable
Manumartin95 Aug 22, 2023
8ee4428
Merge branch 'main' into feature/new_attachments_api
Manumartin95 Sep 4, 2023
0251082
fix: condition to render attachment icon
Manumartin95 Sep 4, 2023
ae1f62b
refactor: update evidence icon props to receive evidence uuid
Manumartin95 Sep 4, 2023
18c5569
Merge branch 'main' into feature/new_attachments_api
Manumartin95 Sep 8, 2023
4d9aaba
feat: add try catch to control upload attachment error
Manumartin95 Sep 11, 2023
345f977
feat: update format file error with new code
Manumartin95 Sep 11, 2023
8b636f7
feat: create attachment error message and remove code error from acti…
Manumartin95 Sep 11, 2023
407ee7b
fix: condition to render attachment icon
Manumartin95 Sep 11, 2023
1278788
feat: create remote file
Manumartin95 Sep 12, 2023
09ff573
feat: create activity evidence component
Manumartin95 Sep 12, 2023
c613874
feat: create function to check types and update with remote file type
Manumartin95 Sep 12, 2023
2367842
refactor: move uuid to shared
Manumartin95 Sep 12, 2023
cc536a4
refactor: update onSubmit condition to set attachment as first elemen…
Manumartin95 Sep 15, 2023
885f3bf
feat: merge files from main
Manumartin95 Dec 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,5 +188,9 @@ The tests are colocated in their respective feature. For example, if we have a `
## TODO

- [ ] Switch to Vitest
- [ ] Review commented out lint rules
- [ ] Review use of any
- [ ] Review use of `as`
- [ ] Review use of `!`
- [ ] Review use of `@ts-ignore`
- [ ] Review use of `eslint-disable`
- [ ] Switch to Zod
4 changes: 3 additions & 1 deletion src/app-providers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import { GlobalErrorBoundary } from './shared/components/global-error-boundary'
import { TntChakraProvider } from './shared/providers/tnt-chakra-provider'
import { AuthProvider } from './shared/contexts/auth-context'
import { PropsWithChildren } from 'react'
import { useTranslation } from 'react-i18next'

export const AppProviders: FC<PropsWithChildren> = (props) => {
const { t } = useTranslation()
return (
<BrowserRouter basename={'tnt'}>
<AuthProvider>
<TntChakraProvider>
<GlobalErrorBoundary>{props.children}</GlobalErrorBoundary>
<GlobalErrorBoundary t={t}>{props.children}</GlobalErrorBoundary>
</TntChakraProvider>
</AuthProvider>
</BrowserRouter>
Expand Down
2 changes: 1 addition & 1 deletion src/app-routes.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { LogoutCmd } from './features/auth/application/logout-cmd'
import { LogoutCmd } from './features/auth/application/logout.cmd'
import { LazyLoginPage } from './features/auth/ui/login-page.lazy'
import { LazyCalendarDesktop } from './features/binnacle/features/activity/ui/calendar-desktop/calendar-desktop.lazy'
import { LazyCalendarMobile } from './features/binnacle/features/activity/ui/calendar-mobile/calendar-mobile.lazy'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { mock } from 'jest-mock-extended'
import { BlockProjectCmd } from './block-project-cmd'
import { BlockProjectCmd } from './block-project.cmd'
import { ProjectRepository } from '../../../../shared/project/domain/project-repository'

describe('BlockProjectCmd', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { mock } from 'jest-mock-extended'
import { UnblockProjectCmd } from './unblock-project-cmd'
import { ProjectRepository } from '../../../../shared/project/domain/project-repository'
import { UnblockProjectCmd } from './unblock-project.cmd'

describe('UnblockProjectCmd', () => {
it('should unblock a project', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { SubmitButton } from '../../../../../../shared/components/form-fields/su
import { useResolve } from '../../../../../../shared/di/use-resolve'
import { DateField } from '../../../../../../shared/components/form-fields/date-field'
import { chrono, parseISO } from '../../../../../../shared/utils/chrono'
import { BlockProjectCmd } from '../../application/block-project-cmd'
import { BlockProjectCmd } from '../../application/block-project.cmd'
import { ProjectModalFormSchema, ProjectModalFormValidationSchema } from './project-modal.schema'
import { useIsMobile } from '../../../../../../shared/hooks/use-is-mobile'
import { Project } from '../../../../../shared/project/domain/project'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { useExecuteUseCaseOnMount } from '../../../../../../shared/arch/hooks/us
import { useSubscribeToUseCase } from '../../../../../../shared/arch/hooks/use-subscribe-to-use-case'
import { Table } from '../../../../../../shared/components/table/table'
import { ColumnsProps } from '../../../../../../shared/components/table/table.types'
import { BlockProjectCmd } from '../../application/block-project-cmd'
import { BlockProjectCmd } from '../../application/block-project.cmd'
import { GetProjectsWithBlockerUserName } from '../../application/get-projects-with-blocker-user-name'
import { UnblockProjectCmd } from '../../application/unblock-project-cmd'
import { UnblockProjectCmd } from '../../application/unblock-project.cmd'
import { ProjectStatus } from '../../domain/project-status'
import { AdaptedProjects, adaptProjectsToTable } from '../projects-page-utils'
import { ProjectsFilterFormCombos } from './combos/projects-combos'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { FC } from 'react'
import { useGetUseCase } from '../../../../../../shared/arch/hooks/use-get-use-case'
import { useResolve } from '../../../../../../shared/di/use-resolve'
import { useIsMobile } from '../../../../../../shared/hooks/use-is-mobile'
import { UnblockProjectCmd } from '../../application/unblock-project-cmd'
import { UnblockProjectCmd } from '../../application/unblock-project.cmd'
import { Project } from '../../../../../shared/project/domain/project'
import { ProjectErrorMessage } from '../../../../../shared/project/domain/services/project-error-message'

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { mock } from 'jest-mock-extended'
import { AuthRepository } from '../domain/auth-repository'
import { LogoutCmd } from './logout-cmd'
import { LogoutCmd } from './logout.cmd'

describe('LogoutCmd', () => {
it('should execute logout using the repository', async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { mock } from 'jest-mock-extended'
import { ActivityRepository } from '../domain/activity-repository'
import { ApproveActivityCmd } from './approve-activity-cmd'
import { ApproveActivityCmd } from './approve-activity.cmd'

describe('ApproveActivityCmd', () => {
it('should approve an activity', async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { mock } from 'jest-mock-extended'
import { ActivityRepository } from '../domain/activity-repository'
import { NewActivity } from '../domain/new-activity'
import { CreateActivityCmd } from './create-activity-cmd'
import { CreateActivityCmd } from './create-activity.cmd'

describe('CreateActivityCmd', () => {
it('should create a new activity', async () => {
Expand All @@ -18,14 +18,13 @@ function setup() {

const newActivity: NewActivity = {
description: 'any-description',
evidences: ['foo'],
billable: true,
interval: {
start: new Date('2000-03-01T09:00:00.000Z'),
end: new Date('2000-03-01T13:00:00.000Z')
},
projectRoleId: 1,
evidence: undefined,
hasEvidences: false
projectRoleId: 1
}

return {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { mock } from 'jest-mock-extended'
import { ActivityRepository } from '../domain/activity-repository'
import { DeleteActivityCmd } from './delete-activity-cmd'
import { DeleteActivityCmd } from './delete-activity.cmd'

describe('DeleteActivityCmd', () => {
it('should delete an activity by id', async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { mock } from 'jest-mock-extended'
import { GetActivityEvidenceQry } from './get-activity-evidence-qry'
import { HttpAttachmentRepository } from '../../attachments/infrastructure/http-attachment-repository'

describe('GetActivityEvidenceQry', () => {
it('should get an activity image by id', async () => {
const { getActivityImageQry, urlToFileConverter } = setup()
const id = 'foo'

await getActivityImageQry.internalExecute(id)

expect(urlToFileConverter.getAttachment).toBeCalledWith(id)
})
})

function setup() {
const httpAttachmentRepository = mock<HttpAttachmentRepository>()

return {
getActivityImageQry: new GetActivityEvidenceQry(httpAttachmentRepository),
urlToFileConverter: httpAttachmentRepository
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Query, UseCaseKey } from '@archimedes/arch'
import { singleton } from 'tsyringe'
import { HttpAttachmentRepository } from '../../attachments/infrastructure/http-attachment-repository'
import { Uuid } from '../../../../../shared/types/uuid'

@UseCaseKey('GetActivityEvidenceQry')
@singleton()
export class GetActivityEvidenceQry extends Query<File, Uuid> {
constructor(private readonly httpAttachmentRepository: HttpAttachmentRepository) {
super()
}

async internalExecute(uuid: Uuid): Promise<File> {
return this.httpAttachmentRepository.getAttachment(uuid)
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { mock } from 'jest-mock-extended'
import { ActivityRepository } from '../domain/activity-repository'
import { UpdateActivity } from '../domain/update-activity'
import { UpdateActivityCmd } from './update-activity-cmd'
import { UpdateActivityCmd } from './update-activity.cmd'

describe('UpdateActivityCmd', () => {
it('should update the activity correctly', async () => {
Expand All @@ -19,14 +19,13 @@ function setup() {
const updateActivity: UpdateActivity = {
id: 1,
description: 'Minutes activity',
evidences: ['foo'],
billable: true,
interval: {
start: new Date('2023-03-01T09:00:00.000Z'),
end: new Date('2023-03-01T13:00:00.000Z')
},
projectRoleId: 1,
evidence: undefined,
hasEvidences: false
projectRoleId: 1
}

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,5 @@ export const ActivityCodeErrors = {
MAX_REGISTRABLE_TIME_PER_ACTIVITY_LIMIT_EXCEEDED:
'MAX_REGISTRABLE_TIME_PER_ACTIVITY_LIMIT_EXCEEDED',
INVALID_ACTIVITY_APPROVAL_STATE: 'INVALID_ACTIVITY_APPROVAL_STATE',
BLOCKED_PROJECT: 'BLOCKED_PROJECT',
ILLEGAL_ARGUMENT: 'ILLEGAL_ARGUMENT'
BLOCKED_PROJECT: 'BLOCKED_PROJECT'
} as const
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ export interface ActivityRepository {
queryParams: GetActivitiesQueryParams
): Promise<ActivityWithProjectRoleId[]>

getActivityEvidence(activityId: Id): Promise<File>

getActivitySummary(interval: DateInterval): Promise<ActivityDaySummary[]>

create(newActivity: NewActivity): Promise<ActivityWithProjectRoleId>
Expand Down
7 changes: 6 additions & 1 deletion src/features/binnacle/features/activity/domain/activity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,22 @@ import { LiteProjectRoleWithProjectId } from '../../search/domain/lite-project-r
import { LiteProjectWithOrganizationId } from '../../search/domain/lite-project-with-organization-id'
import { ActivityInterval } from './activity-interval'
import { ActivityApproval } from './activity-approval'
import { Uuid } from '../../../../../shared/types/uuid'

export interface Activity {
id: Id
description: string
userId: Id
billable: boolean
hasEvidences: boolean
evidences: Uuid[]
organization: Organization
project: LiteProjectWithOrganizationId
projectRole: LiteProjectRoleWithProjectId
approval: ActivityApproval
interval: ActivityInterval
userName?: string
}

export function hasEvidence(activity: Activity): boolean {
return activity.evidences.length > 0
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import { ActivityWithProjectRoleId } from './activity-with-project-role-id'

export type NewActivity = Pick<
ActivityWithProjectRoleId,
'description' | 'billable' | 'projectRoleId' | 'hasEvidences'
'description' | 'billable' | 'projectRoleId' | 'evidences'
> & {
interval: DateInterval
evidence?: File
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ const ActivityErrorTitles: Record<ActivityCodeError, string> = {
MAX_REGISTRABLE_TIME_PER_ACTIVITY_LIMIT_EXCEEDED:
'activity_api_errors.max_registrable_time_per_activity_limit_title',
INVALID_ACTIVITY_APPROVAL_STATE: 'activity_api_errors.invalid_activity_approval_state_title',
BLOCKED_PROJECT: 'activity_api_errors.blocked_project',
ILLEGAL_ARGUMENT: 'activity_api_errors.invalid_file_format_title'
BLOCKED_PROJECT: 'activity_api_errors.blocked_project'
}

const ActivityErrorDescriptions: Record<ActivityCodeError, string> = {
Expand All @@ -36,8 +35,7 @@ const ActivityErrorDescriptions: Record<ActivityCodeError, string> = {
'activity_api_errors.max_registrable_time_per_activity_limit_description',
INVALID_ACTIVITY_APPROVAL_STATE:
'activity_api_errors.invalid_activity_approval_state_description',
BLOCKED_PROJECT: 'activity_api_errors.blocked_project_description',
ILLEGAL_ARGUMENT: 'activity_api_errors.invalid_file_format_description'
BLOCKED_PROJECT: 'activity_api_errors.blocked_project_description'
}

@injectable()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import { ActivityWithProjectRoleId } from './activity-with-project-role-id'

export type UpdateActivity = Pick<
ActivityWithProjectRoleId,
'id' | 'description' | 'billable' | 'projectRoleId' | 'hasEvidences'
'id' | 'description' | 'billable' | 'projectRoleId' | 'evidences'
> & {
interval: DateInterval
evidence?: File
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,6 @@ export class FakeActivityRepository implements ActivityRepository {
return this.activities
}

async getActivityEvidence(): Promise<File> {
return new File([''], 'filename')
}

async getActivitySummary(): Promise<ActivityDaySummary[]> {
return ActivityMother.marchActivitySummary()
}
Expand Down
Loading
Loading