Skip to content

Commit

Permalink
Lock weeks for editing #1249
Browse files Browse the repository at this point in the history
  • Loading branch information
olemp committed Jan 24, 2025
1 parent ea0a806 commit 3105635
Show file tree
Hide file tree
Showing 51 changed files with 241 additions and 74 deletions.
8 changes: 5 additions & 3 deletions client/i18n/en-GB.json
Original file line number Diff line number Diff line change
Expand Up @@ -281,13 +281,15 @@
"employmentStartDateDescription": "The date the user's employment starts. If the user is already employed, set this date to the first day of employment.",
"searchUsersLabel": "Search users..."
},
"missingSubmissions": {
"headerText": "Missing submissions",
"weekStatus": {
"headerText": "Week status",
"teamsReminderMessageTemplate": "You must confirm the following weeks in did: {{periods}}",
"teamsReminderButtonText": "Send reminder in Teams",
"teamsReminderMessageSinglePeriodTemplate": "You must confirm week {{period}} in did.",
"teamsReminderTopicTemplate": "Week {{name}} in did",
"teamsReminderButtonTooltiop": "Send reminder in Teams to all users missing week {{name}}"
"teamsReminderButtonTooltiop": "Send reminder in Teams to all users missing week {{name}}",
"unlockWeekButtonText": "Unlock week",
"lockWeekButtonText": "Lock week"
},
"teams": "Teams",
"teamsEnabledLabel": "Enable Teams functionality",
Expand Down
8 changes: 5 additions & 3 deletions client/i18n/nb.json
Original file line number Diff line number Diff line change
Expand Up @@ -280,13 +280,15 @@
"headerText": "Roller og tillatelser",
"deleteSuccess": "Rollen {{name}} ble slettet."
},
"missingSubmissions": {
"headerText": "Manglende bekreftelser",
"weekStatus": {
"headerText": "Ukestatus",
"teamsReminderMessageTemplate": "Du må bekrefte følgende uker i did: {{periods}}",
"teamsReminderButtonText": "Send påminnelse i Teams",
"teamsReminderMessageSinglePeriodTemplate": "Du må bekreft uke {{period}} i did.",
"teamsReminderTopicTemplate": "Uke {{name}} i did",
"teamsReminderButtonTooltiop": "Send påminnelse i Teams til alle brukere som ikke har bekreftet uke {{name}}"
"teamsReminderButtonTooltiop": "Send påminnelse i Teams til alle brukere som ikke har bekreftet uke {{name}}",
"unlockWeekButtonText": "Lås opp uke",
"lockWeekButtonText": "Lås uke"
},
"reportLinks": {
"headerText": "Rapportkoblinger",
Expand Down
8 changes: 5 additions & 3 deletions client/i18n/nn.json
Original file line number Diff line number Diff line change
Expand Up @@ -281,13 +281,15 @@
"headerText": "Roller og tillatelser",
"deleteSuccess": "Rollen {{name}} vart sletta."
},
"missingSubmissions": {
"headerText": "Manglende bekreftelser",
"weekStatus": {
"headerText": "Ukestatus",
"teamsReminderMessageTemplate": "Du må bekrefte følgende uker i did: {{periods}}",
"teamsReminderButtonText": "Send påminnelse i Teams",
"teamsReminderMessageSinglePeriodTemplate": "Du må bekreft uke {{period}} i did.",
"teamsReminderTopicTemplate": "Uke {{name}} i did",
"teamsReminderButtonTooltiop": "Send påminning i Teams til alle brukarar som ikkje har bekreftet veke {{name}}"
"teamsReminderButtonTooltiop": "Send påminning i Teams til alle brukarar som ikkje har bekreftet veke {{name}}",
"unlockWeekButtonText": "Lås opp uke",
"lockWeekButtonText": "Lås uke"
},
"reportLinks": {
"headerText": "Rapportkoblinger",
Expand Down
7 changes: 2 additions & 5 deletions client/pages/Admin/Admin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React, { FC } from 'react'
import { useTranslation } from 'react-i18next'
import { ApiTokens } from './ApiTokens'
import { Labels } from './Labels'
import { MissingSubmissions } from './MissingSubmissions'
import { WeekStatus } from './WeekStatus'
import { ReportLinks } from './ReportLinks'
import { RolesPermissions } from './RolesPermissions'
import { SubscriptionSettings } from './SubscriptionSettings'
Expand All @@ -22,10 +22,7 @@ export const Admin: FC = () => {
RolesPermissions,
t('admin.rolesPermissions.headerText')
],
missingsubmissions: [
MissingSubmissions,
t('admin.missingSubmissions.headerText')
],
weekStatus: [WeekStatus, t('admin.weekStatus.headerText')],
labels: [Labels, t('common.labelsText')],
subscription: [
SubscriptionSettings,
Expand Down
3 changes: 0 additions & 3 deletions client/pages/Admin/MissingSubmissions/List/List.module.scss

This file was deleted.

This file was deleted.

21 changes: 0 additions & 21 deletions client/pages/Admin/MissingSubmissions/MissingSubmissions.tsx

This file was deleted.

2 changes: 0 additions & 2 deletions client/pages/Admin/MissingSubmissions/index.ts

This file was deleted.

10 changes: 10 additions & 0 deletions client/pages/Admin/WeekStatus/List/List.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.list {
margin: 0;

.actions {
display: flex;
align-items: center;
flex-direction: row;
gap: 10px;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import React from 'react'
import { useTranslation } from 'react-i18next'
import { MissingSubmissionUser } from '../MissingSubmissionUser'
import { TeamsReminderButton } from '../TeamsReminderButton'
import styles from './List.module.scss'
import { IListProps } from './types'
import styles from './List.module.scss'
import { LockWeekButton } from '../LockWeekButton'

export const List: TabComponent<IListProps> = ({ users, period }) => {
const { t } = useTranslation()
Expand All @@ -19,15 +20,15 @@ export const List: TabComponent<IListProps> = ({ users, period }) => {
}
return (
<div className={List.className}>
<TeamsReminderButton
title={t(
'admin.missingSubmissions.teamsReminderButtonTooltiop',
period
)}
period={period}
users={period.users}
topic={t('admin.missingSubmissions.teamsReminderTopicTemplate', period)}
/>
<div className={styles.actions}>
<TeamsReminderButton
title={t('admin.weekStatus.teamsReminderButtonTooltiop', period)}
period={period}
users={period.users}
topic={t('admin.weekStatus.teamsReminderTopicTemplate', period)}
/>
<LockWeekButton period={period} />
</div>
{period.users.map((user, index) => (
<MissingSubmissionUser key={index} user={user} period={period} />
))}
Expand Down
1 change: 1 addition & 0 deletions client/pages/Admin/WeekStatus/List/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './List'
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.lockWeekButton {
margin: 15px 0;
}
22 changes: 22 additions & 0 deletions client/pages/Admin/WeekStatus/LockWeekButton/LockWeekButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Button } from '@fluentui/react-components'
import React from 'react'
import { StyledComponent } from 'types'
import styles from './LockWeekButton.module.scss'
import { ILockWeekButtonProps } from './types'
import { useLockWeekButton } from './useLockWeekButton'

export const LockWeekButton: StyledComponent<ILockWeekButtonProps> = (
props
) => {
const { text, icon, onClick } = useLockWeekButton(props)
return (
<div className={LockWeekButton.className}>
<Button appearance='subtle' icon={icon} onClick={onClick}>
{text}
</Button>
</div>
)
}

LockWeekButton.displayName = 'LockWeekButton'
LockWeekButton.className = styles.lockWeekButton
1 change: 1 addition & 0 deletions client/pages/Admin/WeekStatus/LockWeekButton/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './LockWeekButton'
5 changes: 5 additions & 0 deletions client/pages/Admin/WeekStatus/LockWeekButton/lock-period.gql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
mutation LockPeriod ($periodId: String!, $unlock: Boolean) {
result: lockPeriod(periodId: $periodId, unlock: $unlock) {
success
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
query LockedPeriods {
subscription {
lockedPeriods
}
}
6 changes: 6 additions & 0 deletions client/pages/Admin/WeekStatus/LockWeekButton/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { IButtonProps } from '@fluentui/react'
import { IMissingSubmissionPeriod } from '../types'

export interface ILockWeekButtonProps extends IButtonProps {
period: IMissingSubmissionPeriod
}
52 changes: 52 additions & 0 deletions client/pages/Admin/WeekStatus/LockWeekButton/useLockWeekButton.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { useTranslation } from 'react-i18next'
import { useBoolean } from 'usehooks-ts'
import { getFluentIcon } from 'utils/getFluentIcon'
import { ILockWeekButtonProps } from './types'
import $lockedPeriods from './locked-periods.gql'
import $lockPeriod from './lock-period.gql'
import { useMutation, useQuery } from '@apollo/client'
import { Subscription } from 'types'
import { useEffect } from 'react'

/**
* Component logic hook for the `LockWeekButton` component. Handles
* fetching of locked periods and locking/unlocking of periods.
* Returns the text, icon and click handler for the button.
*
* @param props Props for the `LockWeekButton` component.
*/
export function useLockWeekButton(props: ILockWeekButtonProps) {
const { t } = useTranslation()
const { data } = useQuery<{ subscription: Subscription }>($lockedPeriods, {
fetchPolicy: 'network-only'
})
const [lockPeriod] = useMutation($lockPeriod)
const isLocked = useBoolean(false)

useEffect(() => {
isLocked.setValue(
data?.subscription?.lockedPeriods?.some(
(periodId) => periodId === props.period?.id
)
)
}, [data?.subscription?.lockedPeriods, props.period?.id])

const text = isLocked.value
? t('admin.weekStatus.unlockWeekButtonText')
: t('admin.weekStatus.lockWeekButtonText')
const icon = getFluentIcon(isLocked.value ? 'LockOpen' : 'LockClosed')

/**
* Handles the click event for the button.
*/
const onClick = () => {
lockPeriod({
variables: {
periodId: props.period?.id,
unlock: isLocked.value
}
})
isLocked.toggle()
}
return { text, icon, onClick }
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const TeamsReminderButton: StyledComponent<ITeamsReminderButtonProps> = (
onClick={() => startTeamsConversation()}
{...pick(props, 'title', 'text')}
>
{t('admin.missingSubmissions.teamsReminderButtonText')}
{t('admin.weekStatus.teamsReminderButtonText')}
</Button>
</div>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function useStartTeamsConversation({
useSubscriptionSettings<SubscriptionTeamsSettings>('teams')
const startTeamsConversation = () => {
let message = t(
'admin.missingSubmissions.teamsReminderMessageSinglePeriodTemplate',
'admin.weekStatus.teamsReminderMessageSinglePeriodTemplate',
{ period: period?.name }
)
if (teamsSettings?.missingSubmissionsSinglePeriodText) {
Expand All @@ -39,7 +39,7 @@ export function useStartTeamsConversation({
const periods = first(users)
.periods.map((p) => p.name)
.join(', ')
message = t('admin.missingSubmissions.teamsReminderMessageTemplate', {
message = t('admin.weekStatus.teamsReminderMessageTemplate', {
periods
})
if (teamsSettings?.missingSubmissionsMultiplePeriodsText) {
Expand Down
3 changes: 3 additions & 0 deletions client/pages/Admin/WeekStatus/WeekStatus.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.weekStatus {
margin: 0;
}
21 changes: 21 additions & 0 deletions client/pages/Admin/WeekStatus/WeekStatus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { TabComponent, Tabs } from 'components/Tabs'
import React from 'react'
import styles from './WeekStatus.module.scss'
import { useWeekStatus } from './useWeekStatus'

export const WeekStatus: TabComponent = () => {
const { tabs, defaultSelectedTab } = useWeekStatus()
return (
<div className={WeekStatus.className}>
<Tabs
items={tabs}
vertical
defaultSelectedValue={defaultSelectedTab}
level={3}
/>
</div>
)
}

WeekStatus.displayName = 'WeekStatus'
WeekStatus.className = styles.weekStatus
2 changes: 2 additions & 0 deletions client/pages/Admin/WeekStatus/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './WeekStatus'
export * from './types'
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import { User } from 'types'
import _ from 'underscore'
import * as s from 'underscore.string'
import { arrayMap } from 'utils'
import { List } from './List'
import { List } from './List/List'
import { IMissingSubmissionUser } from './MissingSubmissionUser'
import { IMissingSubmissionPeriod } from './types'
import { useMissingSubmissionsQuery } from './useMissingSubmissionsQuery'
import { useWeekStatusQuery } from './useWeekStatusQuery'

/**
* Maps `User` to `IMissingSubmissionUser`. We don't want to extend
Expand All @@ -37,11 +37,11 @@ const mapUser = (
/**
* Get date periods with missing submissions.
*
* @param data - Data returned by `useMissingSubmissionsQuery`
* @param data - Data returned by `useWeekStatusQuery`
* @param datePeriods - Date periods
*/
const getPeriodsWithMissingSubmissions = (
[periods, users]: ReturnType<typeof useMissingSubmissionsQuery>,
[periods, users]: ReturnType<typeof useWeekStatusQuery>,
datePeriods: IDatePeriod[]
): IMissingSubmissionPeriod[] =>
datePeriods.map((p) => ({
Expand All @@ -65,7 +65,7 @@ const getPeriodsWithMissingSubmissions = (
* @param datePeriods - Date periods
*/
const getUsersWithMissingPeriods = (
[periods, users]: ReturnType<typeof useMissingSubmissionsQuery>,
[periods, users]: ReturnType<typeof useWeekStatusQuery>,
datePeriods: IDatePeriod[]
) =>
arrayMap<User, IMissingSubmissionUser>(users, (user) => {
Expand All @@ -81,9 +81,9 @@ const getUsersWithMissingPeriods = (
})

/**
* Component logic hook for `<MissingSubmissions />`
* Component logic hook for `<WeekStatus />`
*/
export const useMissingSubmissions: ComponentLogicHook<
export const useWeekStatus: ComponentLogicHook<
null,
{
tabs: TabItems
Expand All @@ -92,7 +92,7 @@ export const useMissingSubmissions: ComponentLogicHook<
> = () => {
const { t } = useTranslation()
const { periods: datePeriods } = useTimesheetPeriods()
const data = useMissingSubmissionsQuery()
const data = useWeekStatusQuery()
const periods = getPeriodsWithMissingSubmissions(data, datePeriods)
const users = getUsersWithMissingPeriods(data, datePeriods)
const tabs = useMemo<TabItems>(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { useQuery, WatchQueryFetchPolicy } from '@apollo/client'
import { useTimesheetPeriods } from 'hooks'
import { TimesheetPeriodObject, User } from 'types'
import $missingSubmissions from './missing-submissions.gql'
import $weekStatus from './week-status.gql'

export function useMissingSubmissionsQuery(
export function useWeekStatusQuery(
fetchPolicy: WatchQueryFetchPolicy = 'cache-first'
) {
const { queries } = useTimesheetPeriods()
const { data } = useQuery<{
periods: TimesheetPeriodObject[]
users: User[]
}>($missingSubmissions, {
}>($weekStatus, {
fetchPolicy,
variables: { queries }
})
Expand Down
Loading

0 comments on commit 3105635

Please sign in to comment.