-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* Create button * Move modal to ui-components * Move country selector to features folder * Update country selector exports/imports * Update tupaia-pin.svg * Country selector on modal * Move survey selector to features * Move types * Update survey list component to take care of fetching * Survey selector * Move entity selector to features * Fix types * Entity selector * Styling entity selector * Due date * WIP * WIP * assignee input * Add loading state and save user id * Styling repeat scheduler * Comments placholder * Styling * WIP * Create task route * Create task workflow * Clear form when modal is reopened * Update schemas.ts * remove unused import * Handle reset * Fix datatrak tests * Fix central server tests * Move modal to ui-components * Remove unused import * Remove duplicate file * Fix build * Fix tests * Update packages/central-server/src/apiV2/utilities/constructNewRecordValidationRules.js Co-authored-by: Tom Caiger <caigertom@gmail.com> * Fix error messages * Handle search term in the BE * WIP * WIP * Assignee Id modal * Working assignee * remove unused property * Fix timezone issue * Fix date formatting of filter * remove unused variable * Remove unused variable * Fix casing * Default to showing countries if no primary entity question * Update AssigneeInput.tsx * Show loader when loading project and countries * Fix copy * Exclude internal users * Fix types * Change colour of icon in entity list * Fix modal button types * Fix types --------- Co-authored-by: Tom Caiger <caigertom@gmail.com>
- Loading branch information
Showing
9 changed files
with
353 additions
and
113 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
/* | ||
* Tupaia | ||
* Copyright (c) 2017 - 2024 Beyond Essential Systems Pty Ltd | ||
*/ | ||
|
||
import { useMutation, useQueryClient } from 'react-query'; | ||
import { Task } from '@tupaia/types'; | ||
import { put } from '../api'; | ||
|
||
type Data = Partial<Task>; | ||
|
||
export const useEditTask = (taskId: Task['id'], onSuccess?: () => void) => { | ||
const queryClient = useQueryClient(); | ||
return useMutation<any, Error, Data, unknown>( | ||
(data: Data) => { | ||
return put(`tasks/${taskId}`, { | ||
data, | ||
}); | ||
}, | ||
{ | ||
onSuccess: () => { | ||
queryClient.invalidateQueries('tasks'); | ||
if (onSuccess) onSuccess(); | ||
}, | ||
}, | ||
); | ||
}; |
91 changes: 91 additions & 0 deletions
91
packages/datatrak-web/src/features/Tasks/AssigneeInput.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
/** | ||
* Tupaia | ||
* Copyright (c) 2017 - 2024 Beyond Essential Systems Pty Ltd | ||
*/ | ||
import React, { useState } from 'react'; | ||
import throttle from 'lodash.throttle'; | ||
import styled from 'styled-components'; | ||
import { Country, DatatrakWebSurveyUsersRequest } from '@tupaia/types'; | ||
import { Autocomplete as BaseAutocomplete } from '../../components'; | ||
import { useSurveyUsers } from '../../api'; | ||
import { Survey } from '../../types'; | ||
|
||
const Autocomplete = styled(BaseAutocomplete)` | ||
.MuiFormLabel-root { | ||
font-size: inherit; | ||
font-weight: ${({ theme }) => theme.typography.fontWeightMedium}; | ||
} | ||
.MuiInputBase-root { | ||
font-size: 0.875rem; | ||
} | ||
input::placeholder { | ||
color: ${({ theme }) => theme.palette.text.secondary}; | ||
} | ||
.MuiOutlinedInput-notchedOutline { | ||
border-color: ${({ theme }) => theme.palette.divider}; | ||
} | ||
.MuiInputLabel-asterisk { | ||
color: ${({ theme }) => theme.palette.error.main}; | ||
} | ||
`; | ||
|
||
type User = DatatrakWebSurveyUsersRequest.ResBody[0]; | ||
|
||
interface AssigneeInputProps { | ||
value: string | null; | ||
onChange: (value: User['id'] | null) => void; | ||
inputRef?: React.Ref<any>; | ||
countryCode?: Country['code']; | ||
surveyCode?: Survey['code']; | ||
required?: boolean; | ||
name?: string; | ||
error?: boolean; | ||
} | ||
|
||
export const AssigneeInput = ({ | ||
value, | ||
onChange, | ||
inputRef, | ||
countryCode, | ||
surveyCode, | ||
required, | ||
error, | ||
}: AssigneeInputProps) => { | ||
const [searchValue, setSearchValue] = useState(''); | ||
|
||
const { data: users = [], isLoading } = useSurveyUsers(surveyCode, countryCode, searchValue); | ||
|
||
const onChangeAssignee = (_e, newSelection: User | null) => { | ||
onChange(newSelection?.id ?? null); | ||
}; | ||
|
||
const options = | ||
users?.map(user => ({ | ||
...user, | ||
value: user.id, | ||
label: user.name, | ||
})) ?? []; | ||
|
||
const selection = options.find(option => option.id === value); | ||
|
||
return ( | ||
<Autocomplete | ||
label="Assignee" | ||
options={options} | ||
value={selection} | ||
onChange={onChangeAssignee} | ||
inputRef={inputRef} | ||
name="assignee" | ||
onInputChange={throttle((_, newValue) => { | ||
setSearchValue(newValue); | ||
}, 200)} | ||
inputValue={searchValue} | ||
getOptionLabel={option => option.label} | ||
getOptionSelected={option => option.id === value} | ||
placeholder="Search..." | ||
loading={isLoading} | ||
required={required} | ||
error={error} | ||
/> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
68 changes: 68 additions & 0 deletions
68
packages/datatrak-web/src/features/Tasks/TasksTable/ActionButton.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
/** | ||
* Tupaia | ||
* Copyright (c) 2017 - 2024 Beyond Essential Systems Pty Ltd | ||
*/ | ||
import React from 'react'; | ||
import { TaskStatus } from '@tupaia/types'; | ||
import { generatePath, useLocation } from 'react-router'; | ||
import { Link } from 'react-router-dom'; | ||
import styled from 'styled-components'; | ||
import { Button } from '@tupaia/ui-components'; | ||
import { ROUTES } from '../../../constants'; | ||
import { Task } from '../../../types'; | ||
|
||
const ActionButtonComponent = styled(Button).attrs({ | ||
color: 'primary', | ||
size: 'small', | ||
})` | ||
padding-inline: 1.2rem; | ||
padding-block: 0.4rem; | ||
width: 100%; | ||
.MuiButton-label { | ||
font-size: 0.75rem; | ||
line-height: normal; | ||
} | ||
.cell-content:has(&) { | ||
padding-block: 0.2rem; | ||
padding-inline-start: 1.5rem; | ||
} | ||
`; | ||
|
||
interface ActionButtonProps { | ||
task: Task; | ||
onAssignTask: (task: Task | null) => void; | ||
} | ||
|
||
export const ActionButton = ({ task, onAssignTask }: ActionButtonProps) => { | ||
const location = useLocation(); | ||
if (!task) return null; | ||
const { assigneeId, survey, entity, status } = task; | ||
if (status === TaskStatus.cancelled || status === TaskStatus.completed) return null; | ||
const openAssignTaskModal = () => { | ||
onAssignTask(task); | ||
}; | ||
if (!assigneeId) { | ||
return ( | ||
<ActionButtonComponent variant="outlined" onClick={openAssignTaskModal}> | ||
Assign | ||
</ActionButtonComponent> | ||
); | ||
} | ||
|
||
const surveyLink = generatePath(ROUTES.SURVEY, { | ||
surveyCode: survey.code, | ||
countryCode: entity.countryCode, | ||
}); | ||
return ( | ||
<ActionButtonComponent | ||
component={Link} | ||
to={surveyLink} | ||
variant="contained" | ||
state={{ | ||
from: JSON.stringify(location), | ||
}} | ||
> | ||
Complete | ||
</ActionButtonComponent> | ||
); | ||
}; |
83 changes: 83 additions & 0 deletions
83
packages/datatrak-web/src/features/Tasks/TasksTable/AssignTaskModal.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
/** | ||
* Tupaia | ||
* Copyright (c) 2017 - 2024 Beyond Essential Systems Pty Ltd | ||
*/ | ||
import React from 'react'; | ||
import styled from 'styled-components'; | ||
import { useForm, Controller, FormProvider } from 'react-hook-form'; | ||
import { Modal, ModalCenteredContent } from '@tupaia/ui-components'; | ||
import { AssigneeInput } from '../AssigneeInput'; | ||
import { useEditTask } from '../../../api'; | ||
|
||
const Container = styled(ModalCenteredContent)` | ||
width: 20rem; | ||
max-width: 100%; | ||
margin: 0 auto; | ||
`; | ||
|
||
export const AssignTaskModal = ({ task, onClose }) => { | ||
const formContext = useForm({ | ||
mode: 'onChange', | ||
}); | ||
const { | ||
control, | ||
handleSubmit, | ||
formState: { isValid }, | ||
} = formContext; | ||
|
||
const { mutate: editTask, isLoading } = useEditTask(task?.id, onClose); | ||
|
||
if (!task) return null; | ||
|
||
const modalButtons = [ | ||
{ | ||
text: 'Cancel', | ||
onClick: onClose, | ||
variant: 'outlined', | ||
id: 'cancel', | ||
disabled: isLoading, | ||
}, | ||
{ | ||
text: 'Save', | ||
onClick: handleSubmit(editTask), | ||
id: 'save', | ||
type: 'submit', | ||
disabled: isLoading || !isValid, | ||
}, | ||
]; | ||
|
||
return ( | ||
<> | ||
<Modal | ||
isOpen | ||
onClose={onClose} | ||
title="Assign task" | ||
buttons={modalButtons} | ||
isLoading={isLoading} | ||
> | ||
<Container> | ||
<FormProvider {...formContext}> | ||
<form onSubmit={handleSubmit(editTask)}> | ||
<Controller | ||
name="assignee_id" | ||
control={control} | ||
rules={{ required: 'Required' }} | ||
render={({ value, onChange, ref }, { invalid }) => ( | ||
<AssigneeInput | ||
value={value} | ||
required | ||
onChange={onChange} | ||
inputRef={ref} | ||
countryCode={task?.entity?.countryCode} | ||
surveyCode={task?.survey?.code} | ||
error={invalid} | ||
/> | ||
)} | ||
/> | ||
</form> | ||
</FormProvider> | ||
</Container> | ||
</Modal> | ||
</> | ||
); | ||
}; |
Oops, something went wrong.