Files
construprogress/app/Http/Controllers/OfflineSyncController.php
T
Javier Braña ba614bddbc feat(tasks): complete task management system with Kanban, Calendar, notifications
- Add Task model with subtasks, priorities, status transitions, dates, hours
- Add Comment polymorphic model for tasks/issues/projects
- Livewire components: TaskManager (list+filters), TaskForm (modal), TaskDetail, TaskKanban (drag&drop), TaskCalendar (FullCalendar)
- TaskPolicy with permissions (view/create/edit/delete/assign/manage all)
- Notifications: assigned, status change, overdue, comment added
- Daily overdue notification job scheduled
- Dashboard widget unifies IssueTask + Task
- i18n: en/es/fr/ru (393 keys each)
- Routes, navigation, offline sync support
- 101 tests passing, Pint compliant on new files
2026-08-03 13:44:10 +02:00

127 lines
5.9 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\Feature;
use App\Models\Inspection;
use App\Models\PendingSync;
use App\Models\Phase;
use App\Models\Task;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
class OfflineSyncController extends Controller
{
public function storePending(Request $request)
{
$payload = $request->validate([
'action' => 'required|in:progress_update,inspection,feature_create,media_upload,task_complete,task_create,task_update',
'payload' => 'required|array',
]);
$pending = PendingSync::create([
'user_id' => Auth::id() ?? 1,
'action' => $payload['action'],
'payload' => $payload['payload'],
]);
return response()->json(['queued' => true]);
}
public function sync(Request $request)
{
$user = Auth::user();
$pendings = PendingSync::where('user_id', $user->id)->whereNull('synced_at')->get();
$results = [];
foreach ($pendings as $pending) {
$result = ['id' => $pending->id, 'action' => $pending->action, 'success' => false, 'error' => null];
try {
if ($pending->action === 'progress_update') {
$phase = Phase::find($pending->payload['phase_id']);
if ($phase) {
$phase->progress_percent = $pending->payload['progress'];
$phase->save();
$phase->progressUpdates()->create([
'user_id' => $user->id,
'progress_percent' => $pending->payload['progress'],
'comment' => $pending->payload['comment'] ?? '',
'location' => $pending->payload['location'] ?? null,
]);
}
$result['success'] = true;
} elseif ($pending->action === 'inspection') {
$inspection = Inspection::create($pending->payload);
$result['success'] = true;
$result['data'] = ['inspection_id' => $inspection->id];
} elseif ($pending->action === 'feature_create') {
$feature = Feature::create($pending->payload);
$result['success'] = true;
$result['data'] = ['feature_id' => $feature->id];
} elseif ($pending->action === 'media_upload') {
// Assuming payload has: 'file' (base64), 'path', 'model_type', 'model_id'
// We'll decode the base64 and store the file
if (isset($pending->payload['file'], $pending->payload['path'])) {
$decoded = base64_decode($pending->payload['file']);
if ($decoded !== false) {
$path = Storage::put($pending->payload['path'], $decoded);
// Attach to model if model_type and model_id are provided
if (isset($pending->payload['model_type'], $pending->payload['model_id'])) {
$model = new $pending->payload['model_type'];
$model = $model->find($pending->payload['model_id']);
if ($model) {
$model->media()->create([
'name' => $pending->payload['name'] ?? 'unnamed',
'path' => $path,
'mime_type' => $pending->payload['mime_type'] ?? 'application/octet-stream',
'disk' => 'public',
]);
}
}
$result['success'] = true;
$result['data'] = ['path' => $path];
} else {
$result['error'] = 'Failed to decode base64 file';
}
} else {
$result['error'] = 'Missing file or path in payload';
}
} elseif ($pending->action === 'task_complete') {
// Example: mark a task as complete (you can adjust as needed)
// For now, just log and mark as success
\Log::info('Task completed offline', $pending->payload);
$result['success'] = true;
} elseif ($pending->action === 'task_create') {
$task = Task::create($pending->payload);
$result['success'] = true;
$result['data'] = ['task_id' => $task->id, 'uuid' => $task->uuid];
} elseif ($pending->action === 'task_update') {
$task = Task::find($pending->payload['id'] ?? null);
if ($task) {
// Remove fields that shouldn't be mass updated
$data = $pending->payload;
unset($data['id'], $data['uuid'], $data['created_at'], $data['updated_at'], $data['deleted_at']);
$task->update($data);
$result['success'] = true;
$result['data'] = ['task_id' => $task->id];
} else {
$result['error'] = 'Task not found';
}
} else {
$result['error'] = 'Unknown action type';
}
} catch (\Exception $e) {
$result['error'] = $e->getMessage();
}
if ($result['success']) {
$pending->synced_at = now();
$pending->save();
}
$results[] = $result;
}
return response()->json(['synced' => $results]);
}
}