M7-T06: add meter management UI (timeline, declare swap, edit) to Energy view
This commit is contained in:
@@ -214,6 +214,12 @@ export function useMetrics(uuid: string) {
|
||||
// ===========================================================================
|
||||
|
||||
// Re-exported energy types for consumers
|
||||
export type MeterResponse = components['schemas']['MeterResponse']
|
||||
export type MeterListResponse = components['schemas']['MeterListResponse']
|
||||
export type MeterDeclareRequest = components['schemas']['MeterDeclareRequest']
|
||||
export type MeterPatchRequest = components['schemas']['MeterPatchRequest']
|
||||
export type MeterReason = components['schemas']['MeterReason']
|
||||
|
||||
export type ContractResponse = components['schemas']['ContractResponse']
|
||||
export type ContractDetailResponse = components['schemas']['ContractDetailResponse']
|
||||
export type ContractVersionResponse = components['schemas']['ContractVersionResponse']
|
||||
@@ -434,6 +440,66 @@ export function useRecomputeCosts() {
|
||||
})
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// Meter hooks — typed TanStack Query wrappers for /api/energy/meters.
|
||||
//
|
||||
// Query-key conventions:
|
||||
// ['energy-meters'] — meter list
|
||||
// ===========================================================================
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Query: list all meter epochs
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export function useMeters() {
|
||||
return useQuery({
|
||||
queryKey: ['energy-meters'],
|
||||
queryFn: async () => {
|
||||
const res = await apiClient.GET('/api/energy/meters')
|
||||
return res.data
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Mutation: declare a new meter epoch (swap / home move / initial)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export function useDeclareMeter() {
|
||||
const qc = useQueryClient()
|
||||
return useMutation({
|
||||
mutationFn: (body: MeterDeclareRequest) =>
|
||||
apiClient.POST('/api/energy/meters', { body }),
|
||||
onSuccess: () => {
|
||||
void qc.invalidateQueries({ queryKey: ['energy-meters'] })
|
||||
// Invalidate cost-related queries: a new meter may trigger recompute server-side.
|
||||
void qc.invalidateQueries({ queryKey: ['energy-costs'] })
|
||||
void qc.invalidateQueries({ queryKey: ['energy-costs-summary'] })
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Mutation: update (PATCH) a meter epoch (label / note / started_at)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export function useUpdateMeter() {
|
||||
const qc = useQueryClient()
|
||||
return useMutation({
|
||||
mutationFn: ({ id, body }: { id: number; body: MeterPatchRequest }) =>
|
||||
apiClient.PATCH('/api/energy/meters/{meter_id}', {
|
||||
params: { path: { meter_id: id } },
|
||||
body,
|
||||
}),
|
||||
onSuccess: () => {
|
||||
void qc.invalidateQueries({ queryKey: ['energy-meters'] })
|
||||
// Retroactive started_at correction triggers recompute server-side.
|
||||
void qc.invalidateQueries({ queryKey: ['energy-costs'] })
|
||||
void qc.invalidateQueries({ queryKey: ['energy-costs-summary'] })
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Query: time-range readings for a device (window + limit — never full-table)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user