Просмотр исходного кода

Make the work order agree with the team page about who people are (#273)

* Say what the phone button does, and who fixes it

* Let a work order put somebody on the board

* Call a technician by the name on their account
Bernt Christian Egeland 1 месяц назад
Родитель
Сommit
bacfe518d6

+ 3 - 1
messages/de/service.json

@@ -348,7 +348,9 @@
     "technicians": "Techniker",
     "otherTeamMembers": "Weitere Teammitglieder",
     "makeTechnician": "Macht sie zum Techniker",
-    "addSomeoneNew": "Jemanden hinzufügen"
+    "addSomeoneNew": "Jemanden hinzufügen",
+    "notOnBoard": "Noch nicht auf der Tafel",
+    "putOnBoard": "Auf die Tafel"
   },
   "notifications": {
     "title": "Kundenbenachrichtigungen",

+ 3 - 1
messages/en/service.json

@@ -348,7 +348,9 @@
     "technicians": "Technicians",
     "otherTeamMembers": "Other team members",
     "makeTechnician": "Makes them a technician",
-    "addSomeoneNew": "Add someone new"
+    "addSomeoneNew": "Add someone new",
+    "notOnBoard": "Not on the board yet",
+    "putOnBoard": "Put on board"
   },
   "notifications": {
     "title": "Customer Notifications",

+ 3 - 1
messages/es/service.json

@@ -348,7 +348,9 @@
     "technicians": "Técnicos",
     "otherTeamMembers": "Otros miembros del equipo",
     "makeTechnician": "Lo convierte en técnico",
-    "addSomeoneNew": "Añadir a alguien nuevo"
+    "addSomeoneNew": "Añadir a alguien nuevo",
+    "notOnBoard": "Aún no está en el tablero",
+    "putOnBoard": "Poner en el tablero"
   },
   "notifications": {
     "title": "Notificaciones al cliente",

+ 3 - 1
messages/fr/service.json

@@ -348,7 +348,9 @@
     "technicians": "Techniciens",
     "otherTeamMembers": "Autres membres de l’équipe",
     "makeTechnician": "En fait un technicien",
-    "addSomeoneNew": "Ajouter quelqu’un"
+    "addSomeoneNew": "Ajouter quelqu’un",
+    "notOnBoard": "Pas encore sur le planning",
+    "putOnBoard": "Mettre au planning"
   },
   "notifications": {
     "title": "Notifications client",

+ 3 - 1
messages/it/service.json

@@ -348,7 +348,9 @@
     "technicians": "Tecnici",
     "otherTeamMembers": "Altri membri del team",
     "makeTechnician": "Lo rende un tecnico",
-    "addSomeoneNew": "Aggiungi qualcuno"
+    "addSomeoneNew": "Aggiungi qualcuno",
+    "notOnBoard": "Non ancora sulla lavagna",
+    "putOnBoard": "Metti sulla lavagna"
   },
   "notifications": {
     "title": "Notifiche al cliente",

+ 3 - 1
messages/lt/service.json

@@ -348,7 +348,9 @@
     "technicians": "Technikai",
     "otherTeamMembers": "Kiti komandos nariai",
     "makeTechnician": "Padarys jį techniku",
-    "addSomeoneNew": "Pridėti naują žmogų"
+    "addSomeoneNew": "Pridėti naują žmogų",
+    "notOnBoard": "Dar nėra lentoje",
+    "putOnBoard": "Įtraukti į lentą"
   },
   "notifications": {
     "title": "Kliento pranešimai",

+ 3 - 1
messages/nb/service.json

@@ -348,7 +348,9 @@
     "technicians": "Teknikere",
     "otherTeamMembers": "Andre i teamet",
     "makeTechnician": "Gjør dem til tekniker",
-    "addSomeoneNew": "Legg til noen ny"
+    "addSomeoneNew": "Legg til noen ny",
+    "notOnBoard": "Ikke på tavlen ennå",
+    "putOnBoard": "Sett på tavlen"
   },
   "notifications": {
     "title": "Kundevarsler",

+ 3 - 1
messages/nl/service.json

@@ -348,7 +348,9 @@
     "technicians": "Monteurs",
     "otherTeamMembers": "Andere teamleden",
     "makeTechnician": "Maakt hen monteur",
-    "addSomeoneNew": "Iemand nieuw toevoegen"
+    "addSomeoneNew": "Iemand nieuw toevoegen",
+    "notOnBoard": "Nog niet op het bord",
+    "putOnBoard": "Op het bord zetten"
   },
   "notifications": {
     "title": "Klantmeldingen",

+ 3 - 1
messages/pl/service.json

@@ -348,7 +348,9 @@
     "technicians": "Technicy",
     "otherTeamMembers": "Pozostali członkowie zespołu",
     "makeTechnician": "Uczyni tę osobę technikiem",
-    "addSomeoneNew": "Dodaj nową osobę"
+    "addSomeoneNew": "Dodaj nową osobę",
+    "notOnBoard": "Jeszcze nie na tablicy",
+    "putOnBoard": "Dodaj do tablicy"
   },
   "notifications": {
     "title": "Powiadomienia klienta",

+ 3 - 1
messages/pt-BR/service.json

@@ -348,7 +348,9 @@
     "technicians": "Técnicos",
     "otherTeamMembers": "Outros membros da equipe",
     "makeTechnician": "Torna essa pessoa técnica",
-    "addSomeoneNew": "Adicionar alguém novo"
+    "addSomeoneNew": "Adicionar alguém novo",
+    "notOnBoard": "Ainda não está no quadro",
+    "putOnBoard": "Colocar no quadro"
   },
   "notifications": {
     "title": "Notificações ao cliente",

+ 3 - 1
messages/ru/service.json

@@ -348,7 +348,9 @@
     "technicians": "Механики",
     "otherTeamMembers": "Другие участники",
     "makeTechnician": "Сделает механиком",
-    "addSomeoneNew": "Добавить человека"
+    "addSomeoneNew": "Добавить человека",
+    "notOnBoard": "Ещё не на доске",
+    "putOnBoard": "Добавить на доску"
   },
   "notifications": {
     "title": "Уведомления клиента",

+ 3 - 1
messages/tr/service.json

@@ -348,7 +348,9 @@
     "technicians": "Teknisyenler",
     "otherTeamMembers": "Diğer ekip üyeleri",
     "makeTechnician": "Onu teknisyen yapar",
-    "addSomeoneNew": "Yeni birini ekle"
+    "addSomeoneNew": "Yeni birini ekle",
+    "notOnBoard": "Henüz panoda değil",
+    "putOnBoard": "Panoya ekle"
   },
   "notifications": {
     "title": "Müşteri bildirimleri",

+ 9 - 3
src/app/(authenticated)/settings/team/team-settings.tsx

@@ -561,7 +561,7 @@ export function TeamSettings({
                 )}
                 {/* The way back off. Setting somebody up and signing them out
                     are both one click, and neither hides inside the other. */}
-                {isAdmin && member.role !== 'owner' && technicians.has(member.user.id) && (
+                {isAdmin && technicians.has(member.user.id) && (
                   <Tooltip>
                     <TooltipTrigger asChild>
                       <Button
@@ -577,8 +577,14 @@ export function TeamSettings({
                     <TooltipContent>{t('team.revokeTechnicianTitle')}</TooltipContent>
                   </Tooltip>
                 )}
-                {isAdmin && member.role !== 'owner' && (
-                  /* Shown for everybody, because "can this person have the
+                {isAdmin && (
+                  /* Shown for everybody, the owner included: a one-person
+                     workshop is the desk and the bay, and the owner is the
+                     likeliest technician in it. Only role changes and removal
+                     exclude the owner, because those are the two things that
+                     would lock the workshop out of itself.
+
+                     Shown for everybody else too, because "can this person have the
                      app" is a question about their role, and hiding the
                      button left no way to find out the answer. Disabled with
                      the reason rather than absent. */

+ 26 - 5
src/features/vehicles/Components/service-edit/ScheduleTimesSection.tsx

@@ -22,7 +22,7 @@ import {
   CommandItem,
   CommandList,
 } from '@/components/ui/command'
-import { Check, ChevronsUpDown, Clock, Plus, Settings } from 'lucide-react'
+import { Check, ChevronsUpDown, Clock, Plus, Settings, UserPlus } from 'lucide-react'
 import { toast } from 'sonner'
 import { DateTimePicker } from '@/components/ui/datetime-picker'
 import {
@@ -309,11 +309,32 @@ export function ScheduleTimesSection({
                     ))}
                   </CommandGroup>
                 )}
+                {/* Colleagues who are not on the board yet.
+                    This list was computed and then not rendered, which left no
+                    way at all to put somebody on a job from here: the only
+                    route was a phone icon on the team page, labelled as
+                    something else. It was dropped because choosing a colleague
+                    quietly turned them into a technician, and that is the part
+                    worth keeping fixed, so the heading says what will happen
+                    rather than the click doing it silently. */}
+                {unlinkedMembers.length > 0 && (
+                  <CommandGroup heading={t('notOnBoard')}>
+                    {unlinkedMembers.map((member) => (
+                      <CommandItem
+                        key={member.id}
+                        value={member.name ?? ''}
+                        disabled={creating}
+                        onSelect={() => handleMemberSelect(member)}
+                      >
+                        <UserPlus className="mr-2 h-4 w-4 text-muted-foreground" />
+                        <span className="flex-1">{member.name}</span>
+                        <span className="text-muted-foreground text-xs">{t('putOnBoard')}</span>
+                      </CommandItem>
+                    ))}
+                  </CommandGroup>
+                )}
                 {/* Adding somebody is one workflow, and this is a door into
-                    it rather than a fourth way of doing it. The picker used to
-                    create people itself: choosing an office colleague quietly
-                    made them a technician, and typing a name made a second
-                    kind nobody had asked about. */}
+                    it rather than a fourth way of doing it. */}
                 <CommandGroup>
                   <CommandItem value="__add_person__" onSelect={() => setAddingPerson(true)}>
                     <Plus className="mr-2 h-4 w-4" />

+ 18 - 1
src/features/workboard/Actions/technicianActions.ts

@@ -25,9 +25,26 @@ export async function getTechnicians() {
           organizationId: true,
           createdAt: true,
           updatedAt: true,
+          user: { select: { name: true, email: true } },
         },
       })
-      return technicians
+
+      /**
+       * The account's name wins over the copy stored on the row.
+       *
+       * A technician row carries its own name, written once when the row was
+       * made and never since. Rename somebody, or attach an existing row to a
+       * different account, and the two drift: the work board went on calling
+       * one member "Petter" while the team page called the same person John
+       * Doe, and nobody could tell they were looking at one person.
+       *
+       * Only when a row belongs to an account. A board-only technician has no
+       * account to ask, and the stored name is the only name there is.
+       */
+      return technicians.map(({ user, ...technician }) => ({
+        ...technician,
+        name: user?.name || user?.email || technician.name,
+      }))
     },
     {
       requiredPermissions: [