fix: proširi bilješke na članove tima i osvježi kalendar
Widget Bilješke sada omogućuje odabir više članova tima (ne samo servisera), a backend validacija i testovi su usklađeni. Dodatno, nakon realtime service_note notifikacije sada se osvježava service-notes store, te create flow više ne briše lokalne bilješke kada odgovor vrati praznu listu. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -24,7 +24,7 @@ export default function ServiceNotesWidget({
|
||||
canManageRecipients = false,
|
||||
activeTasks = [],
|
||||
activeWorkOrders = [],
|
||||
servicers = [],
|
||||
teamMembers = [],
|
||||
onCreate,
|
||||
onClose,
|
||||
}) {
|
||||
@@ -156,7 +156,7 @@ export default function ServiceNotesWidget({
|
||||
className="w-full rounded-md border border-border-hairline bg-canvas-base px-2 py-1.5 text-xs text-text-main"
|
||||
>
|
||||
<option value="self">Notifikacija samo meni</option>
|
||||
{canManageRecipients && <option value="member">Notifikacija serviserima</option>}
|
||||
{canManageRecipients && <option value="member">Notifikacija odabranim članovima tima</option>}
|
||||
{canManageRecipients && <option value="team">Notifikacija svim članovima tima</option>}
|
||||
</select>
|
||||
{canManageRecipients && audience === 'member' && (
|
||||
@@ -167,10 +167,10 @@ export default function ServiceNotesWidget({
|
||||
const selected = Array.from(event.currentTarget.selectedOptions).map((option) => option.value);
|
||||
setTargetUsers(selected);
|
||||
}}
|
||||
size={Math.min(6, Math.max(3, servicers.length || 3))}
|
||||
size={Math.min(6, Math.max(3, teamMembers.length || 3))}
|
||||
className="w-full rounded-md border border-border-hairline bg-canvas-base px-2 py-1.5 text-xs text-text-main"
|
||||
>
|
||||
{servicers.map((member) => (
|
||||
{teamMembers.map((member) => (
|
||||
<option key={member.id} value={member.id}>
|
||||
{member.full_name || member.email}
|
||||
</option>
|
||||
@@ -179,7 +179,7 @@ export default function ServiceNotesWidget({
|
||||
)}
|
||||
{canManageRecipients && audience === 'member' && (
|
||||
<p className="text-[10px] text-text-muted">
|
||||
Držite Ctrl (ili Cmd) za odabir više servisera.
|
||||
Držite Ctrl (ili Cmd) za odabir više članova tima.
|
||||
</p>
|
||||
)}
|
||||
<button
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useEffect, useMemo, useState } from 'preact/hooks';
|
||||
import { useStore } from '@nanostores/preact';
|
||||
import { $tasks } from '../../stores/taskStore';
|
||||
import { $user } from '../../stores/authStore';
|
||||
import { $workOrdersWithVehicle, fetchServicers } from '../../stores/fleetDashboardStore';
|
||||
import { $workOrdersWithVehicle, fetchTeamMembers } from '../../stores/fleetDashboardStore';
|
||||
import {
|
||||
$serviceNotes,
|
||||
$serviceNotesLoading,
|
||||
@@ -30,7 +30,7 @@ export default function TaskCalendarPortal() {
|
||||
const notes = useStore($serviceNotes);
|
||||
const notesLoading = useStore($serviceNotesLoading);
|
||||
const user = useStore($user);
|
||||
const [servicers, setServicers] = useState([]);
|
||||
const [teamMembers, setTeamMembers] = useState([]);
|
||||
|
||||
const isServiser = Boolean(user?.is_serviser);
|
||||
const isTeamMember = Boolean(user?.is_team_member);
|
||||
@@ -82,18 +82,18 @@ export default function TaskCalendarPortal() {
|
||||
|
||||
useEffect(() => {
|
||||
if (!canManageRecipients) {
|
||||
setServicers([]);
|
||||
setTeamMembers([]);
|
||||
return;
|
||||
}
|
||||
let active = true;
|
||||
fetchServicers()
|
||||
fetchTeamMembers()
|
||||
.then((rows) => {
|
||||
if (!active) return;
|
||||
setServicers(Array.isArray(rows) ? rows : []);
|
||||
setTeamMembers(Array.isArray(rows) ? rows : []);
|
||||
})
|
||||
.catch(() => {
|
||||
if (!active) return;
|
||||
setServicers([]);
|
||||
setTeamMembers([]);
|
||||
});
|
||||
return () => {
|
||||
active = false;
|
||||
@@ -123,7 +123,7 @@ export default function TaskCalendarPortal() {
|
||||
canManageRecipients={canManageRecipients}
|
||||
activeTasks={activeTasks}
|
||||
activeWorkOrders={activeWorkOrders}
|
||||
servicers={servicers}
|
||||
teamMembers={teamMembers}
|
||||
onCreate={createServiceNote}
|
||||
onClose={closeServiceNote}
|
||||
/>
|
||||
|
||||
@@ -3,6 +3,7 @@ import Pusher from 'pusher-js';
|
||||
import { api } from '../services/apiClient';
|
||||
import { $accessToken, $user } from './authStore';
|
||||
import { showToast } from './toastStore';
|
||||
import { fetchServiceNotes } from './serviceNotesStore';
|
||||
|
||||
export const $notifications = atom([]);
|
||||
export const $isRealtimeConnected = atom(false);
|
||||
@@ -84,6 +85,9 @@ function attachChannelHandlers(channel) {
|
||||
}
|
||||
|
||||
$notifications.set([next, ...existing]);
|
||||
if (next?.metadata?.entity_type === 'service_note') {
|
||||
fetchServiceNotes().catch(() => {});
|
||||
}
|
||||
showToast(next.title, next.level === 'warning' || next.level === 'critical' ? 'error' : 'success');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ export async function fetchServiceNotes() {
|
||||
export async function createServiceNote(data) {
|
||||
const payload = await api.post('fleet/service-notes/', data ?? {});
|
||||
const nextNotes = Array.isArray(payload?.notes) ? payload.notes : null;
|
||||
if (nextNotes) {
|
||||
if (nextNotes && nextNotes.length > 0) {
|
||||
$serviceNotes.set(nextNotes);
|
||||
} else {
|
||||
await fetchServiceNotes();
|
||||
|
||||
Reference in New Issue
Block a user