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

Lisätään työaikakirjaukseen luonti/muokkaustiedot #6200

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions frontend/src/e2e-test/dev-api/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1000,6 +1000,8 @@ export class Fixture {
occupancyCoefficient: 7,
type: 'PRESENT',
departedAutomatically: false,
modifiedAt: HelsinkiDateTime.now(),
modifiedBy: systemInternalUser.id,
...initial
})
}
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/e2e-test/generated/api-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -941,6 +941,8 @@ export interface DevStaffAttendance {
employeeId: EmployeeId
groupId: GroupId | null
id: StaffAttendanceRealtimeId
modifiedAt: HelsinkiDateTime | null
modifiedBy: EvakaUserId | null
occupancyCoefficient: number
type: StaffAttendanceType
}
Expand Down Expand Up @@ -1576,7 +1578,8 @@ export function deserializeJsonDevStaffAttendance(json: JsonOf<DevStaffAttendanc
return {
...json,
arrived: HelsinkiDateTime.parseIso(json.arrived),
departed: (json.departed != null) ? HelsinkiDateTime.parseIso(json.departed) : null
departed: (json.departed != null) ? HelsinkiDateTime.parseIso(json.departed) : null,
modifiedAt: (json.modifiedAt != null) ? HelsinkiDateTime.parseIso(json.modifiedAt) : null
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,16 +282,31 @@ export class UnitStaffAttendancesTable extends Element {
)
}

async assertTooltip(
async assertArrivalTimeTooltip(
row: number,
date: LocalDate,
expectedTooltipText: string
): Promise<void> {
const cell = this.#attendanceCell(date, row)
await cell.hover()
const arrivalTime = cell.findByDataQa('arrival-time')
await arrivalTime.hover()

await arrivalTime
.findByDataQa('arrival-time-tooltip')
.assertTextEquals(expectedTooltipText)
}

async assertDepartureTimeTooltip(
row: number,
date: LocalDate,
expectedTooltipText: string
): Promise<void> {
const cell = this.#attendanceCell(date, row)
const departureTime = cell.findByDataQa('departure-time')
await departureTime.hover()

await cell
.findByDataQa('attendance-tooltip')
await departureTime
.findByDataQa('departure-time-tooltip')
.assertTextEquals(expectedTooltipText)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,9 @@ describe('Realtime staff attendances', () => {
type: 'OVERTIME',
arrived: yesterday.toHelsinkiDateTime(LocalTime.of(7, 0)),
departed: yesterday.toHelsinkiDateTime(LocalTime.of(20, 0)),
departedAutomatically: true
departedAutomatically: true,
modifiedAt: null,
modifiedBy: null
}).save()

await Fixture.realtimeStaffAttendance({
Expand All @@ -311,7 +313,9 @@ describe('Realtime staff attendances', () => {
type: 'OVERTIME',
arrived: yesterday.toHelsinkiDateTime(LocalTime.of(8, 0)),
departed: yesterday.toHelsinkiDateTime(LocalTime.of(16, 0)),
departedAutomatically: false
departedAutomatically: false,
modifiedAt: null,
modifiedBy: null
}).save()

await Fixture.realtimeStaffAttendance({
Expand All @@ -320,7 +324,9 @@ describe('Realtime staff attendances', () => {
type: 'OVERTIME',
arrived: yesterday.subDays(1).toHelsinkiDateTime(LocalTime.of(9, 0)),
departed: yesterday.subDays(1).toHelsinkiDateTime(LocalTime.of(15, 0)),
departedAutomatically: false
departedAutomatically: false,
modifiedAt: null,
modifiedBy: null
}).save()

await Fixture.staffAttendancePlan({
Expand Down Expand Up @@ -348,7 +354,11 @@ describe('Realtime staff attendances', () => {
attendances: [['07:00', '20:00*']]
})

await staffAttendances.assertTooltip(0, yesterday, 'Automaattikatkaistu')
await staffAttendances.assertDepartureTimeTooltip(
0,
yesterday,
'Automaattikatkaistu'
)

const modal = await staffAttendances.openDetails(0, yesterday)
await modal.setDepartureTime(0, '15:00')
Expand All @@ -359,6 +369,11 @@ describe('Realtime staff attendances', () => {
name: staffName(groupStaff),
attendances: [['07:00', '15:00']]
})
await staffAttendances.assertDepartureTimeTooltip(
0,
yesterday,
'Muokattu 30.03.2022 18:00, Esimies Essi'
)
})
})
describe('Details modal', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ import {
DevEmployee,
StaffAttendancePlanId
} from '../../generated/api-types'
import { UnitPage } from '../../pages/employee/units/unit'
import MobileNav from '../../pages/mobile/mobile-nav'
import {
StaffAttendanceEditPage,
StaffAttendancePage
} from '../../pages/mobile/staff-page'
import { pairMobileDevice } from '../../utils/mobile'
import { Page } from '../../utils/page'
import { employeeLogin } from '../../utils/user'

let page: Page
let nav: MobileNav
Expand Down Expand Up @@ -125,7 +127,8 @@ const initPages = async (

describe('Realtime staff attendance page', () => {
test('Staff member can be marked as arrived and departed', async () => {
await initPages(HelsinkiDateTime.of(2022, 5, 5, 6, 0))
const date = LocalDate.of(2022, 5, 5)
await initPages(HelsinkiDateTime.fromLocal(date, LocalTime.of(6, 0)))
const arrivalTime = '05:59'
const departureTime = '12:45'

Expand All @@ -145,7 +148,7 @@ describe('Realtime staff attendance page', () => {
`Paikalla ${arrivalTime}–`
])

await initPages(HelsinkiDateTime.of(2022, 5, 5, 13, 30))
await initPages(HelsinkiDateTime.fromLocal(date, LocalTime.of(13, 30)))
await staffAttendancePage.assertPresentStaffCount(1)

await staffAttendancePage.selectTab('present')
Expand All @@ -158,6 +161,33 @@ describe('Realtime staff attendance page', () => {
])
await staffAttendancePage.goBackFromMemberPage()
await staffAttendancePage.assertPresentStaffCount(0)

const desktopPage = await Page.open({
mockedTime: HelsinkiDateTime.fromLocal(date, LocalTime.of(13, 30))
})
await employeeLogin(desktopPage, staffFixture)
const unitPage = new UnitPage(desktopPage)
await unitPage.navigateToUnit(testDaycare2.id)
const calendarPage = await unitPage.openCalendarPage()
await calendarPage.selectGroup(testDaycareGroup.id)
const staffAttendances = calendarPage.staffAttendances

await staffAttendances.assertTableRow({
rowIx: 0,
nth: date.getIsoDayOfWeek() - 1,
name: `${staffFixture.lastName} ${staffFixture.firstName}`,
attendances: [[arrivalTime, departureTime]]
})
await staffAttendances.assertArrivalTimeTooltip(
0,
date,
'Merkintä luotu 05.05.2022 06:00, testMobileDevice'
)
await staffAttendances.assertDepartureTimeTooltip(
0,
date,
'Merkintä luotu 05.05.2022 13:30, testMobileDevice'
)
})

test('Occupancy effect can not be unchecked on arrival if it has been given permanently but can be edited', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import classNames from 'classnames'
import groupBy from 'lodash/groupBy'
import isEqual from 'lodash/isEqual'
import mapValues from 'lodash/mapValues'
import sortBy from 'lodash/sortBy'
import uniq from 'lodash/uniq'
Expand Down Expand Up @@ -32,6 +33,7 @@ import {
StaffAttendanceExternalId,
StaffAttendanceRealtimeId
} from 'lib-common/generated/api-types/shared'
import { EvakaUser } from 'lib-common/generated/api-types/user'
import HelsinkiDateTime from 'lib-common/helsinki-date-time'
import LocalDate from 'lib-common/local-date'
import LocalTime from 'lib-common/local-time'
Expand All @@ -43,7 +45,7 @@ import AddButton from 'lib-components/atoms/buttons/AddButton'
import { IconOnlyButton } from 'lib-components/atoms/buttons/IconOnlyButton'
import { Table, Tbody } from 'lib-components/layout/Table'
import { FixedSpaceRow } from 'lib-components/layout/flex-helpers'
import { fontWeights } from 'lib-components/typography'
import { fontWeights, Italic, P } from 'lib-components/typography'
import { BaseProps } from 'lib-components/utils'
import { defaultMargins } from 'lib-components/white-space'
import { colors } from 'lib-customizations/common'
Expand Down Expand Up @@ -202,7 +204,17 @@ export default React.memo(function StaffAttendanceTable({
}
name={row.name}
operationalDays={operationalDays}
attendances={row.attendances}
attendances={row.attendances.map((attendance) => ({
...attendance,
arrivedAddedAt: null,
arrivedAddedBy: null,
arrivedModifiedAt: null,
arrivedModifiedBy: null,
departedAddedAt: null,
departedAddedBy: null,
departedModifiedAt: null,
departedModifiedBy: null
}))}
groupFilter={groupFilter}
openDetails={(date: LocalDate) => {
setDetailsModalConfig({
Expand Down Expand Up @@ -497,6 +509,14 @@ interface AttendanceRowAttendance {
groupId: GroupId | null
departedAutomatically: boolean
type: StaffAttendanceType
arrivedAddedAt: HelsinkiDateTime | null
arrivedAddedBy: EvakaUser | null
arrivedModifiedAt: HelsinkiDateTime | null
arrivedModifiedBy: EvakaUser | null
departedAddedAt: HelsinkiDateTime | null
departedAddedBy: EvakaUser | null
departedModifiedAt: HelsinkiDateTime | null
departedModifiedBy: EvakaUser | null
}

interface AttendanceRowProps extends BaseProps {
Expand Down Expand Up @@ -527,12 +547,63 @@ const AttendanceRow = React.memo(function AttendanceRow({
const { i18n } = useTranslation()
const today = LocalDate.todayInHelsinkiTz()

const attendanceTooltipText = (attendance: AttendanceRowAttendance) =>
attendance.departedAutomatically ? (
const timeTooltipText = ({
addedAt,
addedBy,
modifiedAt,
modifiedBy
}: {
addedAt: HelsinkiDateTime | null
addedBy: EvakaUser | null
modifiedAt: HelsinkiDateTime | null
modifiedBy: EvakaUser | null
}) => {
if (
addedAt === null &&
addedBy === null &&
modifiedAt === null &&
modifiedBy === null
) {
return undefined
}
return (
<>
{addedAt !== null && addedBy !== null && (
<P>
{i18n.unit.staffAttendance.addedAt} {addedAt.format()},{' '}
<Italic>{addedBy.name}</Italic>
</P>
)}
{modifiedAt !== null &&
modifiedBy !== null &&
(addedAt === null ||
!addedAt.isEqual(modifiedAt) ||
!isEqual(addedBy, modifiedBy)) && (
<P>
{i18n.unit.staffAttendance.modifiedAt} {modifiedAt.format()},{' '}
<Italic>{modifiedBy.name}</Italic>
</P>
)}
</>
)
}
const departureTooltipText = (attendance: AttendanceRowAttendance) => {
const timeTooltip = timeTooltipText({
addedAt: attendance.departedAddedAt,
addedBy: attendance.departedAddedBy,
modifiedAt: attendance.departedModifiedAt,
modifiedBy: attendance.departedModifiedBy
})

return timeTooltip !== undefined || attendance.departedAutomatically ? (
<div>
<div>{i18n.unit.staffAttendance.departedAutomatically}</div>
{timeTooltip !== undefined && timeTooltip}
{attendance.departedAutomatically && (
<P>{i18n.unit.staffAttendance.departedAutomatically}</P>
)}
</div>
) : undefined
}

return (
<DayTr data-qa={`attendance-row-${rowIndex}`}>
Expand Down Expand Up @@ -621,23 +692,31 @@ const AttendanceRow = React.memo(function AttendanceRow({
<AttendanceTimes data-qa="attendance-day">
{attendancesForToday.length > 0 ? (
attendancesForToday.map((attendance, i) => {
const tooltip = attendanceTooltipText(attendance)
return (
<Tooltip
key={i}
tooltip={tooltip}
data-qa="attendance-tooltip"
>
<AttendanceCell>
<AttendanceTime data-qa="arrival-time">
<AttendanceCell key={i}>
<AttendanceTime data-qa="arrival-time">
<Tooltip
tooltip={timeTooltipText({
addedAt: attendance.arrivedAddedAt,
addedBy: attendance.arrivedAddedBy,
modifiedAt: attendance.arrivedModifiedAt,
modifiedBy: attendance.arrivedModifiedBy
})}
data-qa="arrival-time-tooltip"
>
{renderTime(attendance.arrived, date)}
</AttendanceTime>
<AttendanceTime data-qa="departure-time">
</Tooltip>
</AttendanceTime>
<AttendanceTime data-qa="departure-time">
<Tooltip
tooltip={departureTooltipText(attendance)}
data-qa="departure-time-tooltip"
>
{renderTime(attendance.departed, date)}
{tooltip ? `*` : ''}
</AttendanceTime>
</AttendanceCell>
</Tooltip>
{attendance.departedAutomatically ? `*` : ''}
</Tooltip>
</AttendanceTime>
</AttendanceCell>
)
})
) : (
Expand Down
14 changes: 13 additions & 1 deletion frontend/src/lib-common/generated/api-types/attendance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,16 @@ export interface ArrivalsRequest {
*/
export interface Attendance {
arrived: HelsinkiDateTime
arrivedAddedAt: HelsinkiDateTime | null
arrivedAddedBy: EvakaUser | null
arrivedModifiedAt: HelsinkiDateTime | null
arrivedModifiedBy: EvakaUser | null
departed: HelsinkiDateTime | null
departedAddedAt: HelsinkiDateTime | null
departedAddedBy: EvakaUser | null
departedAutomatically: boolean
departedModifiedAt: HelsinkiDateTime | null
departedModifiedBy: EvakaUser | null
groupId: GroupId | null
id: StaffAttendanceRealtimeId
occupancyCoefficient: number
Expand Down Expand Up @@ -465,7 +473,11 @@ export function deserializeJsonAttendance(json: JsonOf<Attendance>): Attendance
return {
...json,
arrived: HelsinkiDateTime.parseIso(json.arrived),
departed: (json.departed != null) ? HelsinkiDateTime.parseIso(json.departed) : null
arrivedAddedAt: (json.arrivedAddedAt != null) ? HelsinkiDateTime.parseIso(json.arrivedAddedAt) : null,
arrivedModifiedAt: (json.arrivedModifiedAt != null) ? HelsinkiDateTime.parseIso(json.arrivedModifiedAt) : null,
departed: (json.departed != null) ? HelsinkiDateTime.parseIso(json.departed) : null,
departedAddedAt: (json.departedAddedAt != null) ? HelsinkiDateTime.parseIso(json.departedAddedAt) : null,
departedModifiedAt: (json.departedModifiedAt != null) ? HelsinkiDateTime.parseIso(json.departedModifiedAt) : null
}
}

Expand Down
Loading
Loading