- Implement Monthly Entry interface with full data entry grid
- Add batch save with validation and statistics for monthly results
- Support daily comments per day per test
- Add result status indicators and validation summaries
- Consolidate Entry API controller
- Refactor EntryApiController to handle both daily/monthly operations
- Add batch save endpoints with comprehensive validation
- Implement statistics calculation for result entries
- Add Control Test master data management
- Create MasterControlsController for CRUD operations
- Add dialog forms for control test configuration
- Implement control-test associations with QC parameters
- Refactor Report API and views
- Implement new report index with Levey-Jennings charts placeholder
- Add monthly report functionality with result statistics
- Include QC summary with mean, SD, and CV calculations
- UI improvements
- Overhaul dashboard with improved layout
- Update daily entry interface with inline editing
- Enhance master data management with DaisyUI components
- Add proper modal dialogs and form validation
- Database and seeding
- Update migration for control_tests table schema
- Remove redundant migration and seed files
- Update seeders with comprehensive test data
- Documentation
- Update CLAUDE.md with comprehensive project documentation
- Add architecture overview and conventions
BREAKING CHANGES:
- Refactored Entry API endpoints structure
- Removed ReportApiController::view() - consolidated into new report index
78 lines
4.3 KiB
PHP
78 lines
4.3 KiB
PHP
<dialog class="modal modal-bottom sm:modal-middle" :class="{ 'modal-open': showModal }">
|
|
<div class="modal-box p-5 border border-base-300 shadow-2xl bg-base-100 max-w-sm">
|
|
<h3 class="font-bold text-base mb-3 flex items-center gap-2 text-base-content">
|
|
<i class="fa-solid fa-vial text-primary text-sm"></i>
|
|
<span x-text="form.controlId ? 'Edit Control' : 'New Control'"></span>
|
|
</h3>
|
|
|
|
<div class="space-y-2">
|
|
<div class="form-control">
|
|
<label class="label py-1">
|
|
<span class="label-text-alt font-semibold text-base-content/70">Control Name</span>
|
|
</label>
|
|
<input type="text"
|
|
class="input input-bordered input-sm w-full focus:outline-none focus:ring-2 focus:ring-primary/50 focus:border-primary bg-base-200 border-base-300 text-base-content placeholder:opacity-50"
|
|
:class="{'border-error': errors.controlName}" x-model="form.controlName" list="control-names-list"
|
|
placeholder="Enter control name" />
|
|
<datalist id="control-names-list">
|
|
<template x-for="name in uniqueControlNames" :key="name">
|
|
<option :value="name" x-text="name"></option>
|
|
</template>
|
|
</datalist>
|
|
<template x-if="errors.controlName">
|
|
<label class="label">
|
|
<span class="label-text-alt text-error" x-text="errors.controlName"></span>
|
|
</label>
|
|
</template>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-2 gap-3">
|
|
<div class="form-control">
|
|
<label class="label py-1">
|
|
<span class="label-text-alt font-semibold text-base-content/70">Lot Number</span>
|
|
</label>
|
|
<input type="text"
|
|
class="input input-bordered input-sm w-full focus:outline-none focus:ring-1 focus:ring-primary/40 focus:border-primary bg-base-200 border-base-300 text-base-content placeholder:opacity-50"
|
|
x-model="form.lot" placeholder="e.g., LOT12345" />
|
|
</div>
|
|
|
|
<div class="form-control">
|
|
<label class="label py-1">
|
|
<span class="label-text-alt font-semibold text-base-content/70">Expiry Date</span>
|
|
</label>
|
|
<input type="date"
|
|
class="input input-bordered input-sm w-full focus:outline-none focus:ring-1 focus:ring-primary/40 focus:border-primary bg-base-200 border-base-300 text-base-content"
|
|
x-model="form.expDate" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-control">
|
|
<label class="label py-1">
|
|
<span class="label-text-alt font-semibold text-base-content/70">Producer</span>
|
|
</label>
|
|
<input type="text"
|
|
class="input input-bordered input-sm w-full focus:outline-none focus:ring-1 focus:ring-primary/40 focus:border-primary bg-base-200 border-base-300 text-base-content placeholder:opacity-50"
|
|
x-model="form.producer" list="producers-list" placeholder="Enter producer name" />
|
|
<datalist id="producers-list">
|
|
<template x-for="producer in uniqueProducers" :key="producer">
|
|
<option :value="producer" x-text="producer"></option>
|
|
</template>
|
|
</datalist>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="modal-action mt-5">
|
|
<button class="btn btn-sm btn-ghost opacity-70" @click="closeModal()">Cancel</button>
|
|
<button class="btn btn-sm btn-primary gap-2 shadow-md shadow-primary/20 font-medium"
|
|
:class="{'loading': loading}" @click="save()" :disabled="loading">
|
|
<template x-if="!loading">
|
|
<span><i class="fa-solid fa-save"></i> Save</span>
|
|
</template>
|
|
<template x-if="loading">
|
|
<span>Saving...</span>
|
|
</template>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<form method="dialog" class="modal-backdrop bg-black/60" @click="closeModal()"></form>
|
|
</dialog> |