712 lines
24 KiB
PHP
712 lines
24 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Models\User;
|
|
use App\Models\SalesRoute;
|
|
use App\Models\SalesRouteSummary;
|
|
use App\Models\Waypoint;
|
|
use App\Helpers\GeoHelper;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Support\Facades\Hash;
|
|
use Carbon\Carbon;
|
|
|
|
class GeoTrackController extends Controller
|
|
{
|
|
/**
|
|
* GET /api/sales-routes
|
|
* Get all routes with optional filters
|
|
*/
|
|
public function index(Request $request): JsonResponse
|
|
{
|
|
$query = SalesRoute::with('user:id,employee_id,name,color');
|
|
|
|
// Filter by date
|
|
if ($request->has('date')) {
|
|
$query->whereDate('date', $request->date);
|
|
}
|
|
|
|
// Filter by salesId
|
|
// Filter by salesId
|
|
if ($request->has('salesId')) {
|
|
$user = User::where('employee_id', $request->salesId)->first(['id']);
|
|
if ($user) {
|
|
$query->where('user_id', $user->id);
|
|
} else {
|
|
// If user not found with that employee_id, return empty result immediately
|
|
// preventing return of all routes or failing
|
|
$query->where('user_id', 'non_existent_id');
|
|
}
|
|
}
|
|
|
|
$routes = $query->orderBy('date', 'desc')->get();
|
|
|
|
// Format routes with waypoints
|
|
$formattedRoutes = $routes->map(function ($route) use ($request) {
|
|
$waypoints = $route->waypoints;
|
|
|
|
// Filter waypoints by time if specified
|
|
if ($request->has('timeFrom') || $request->has('timeTo')) {
|
|
$waypoints = $waypoints->filter(function ($wp) use ($request) {
|
|
$wpTime = Carbon::parse($wp->recorded_at)->format('H:i');
|
|
if ($request->timeFrom && $wpTime < $request->timeFrom)
|
|
return false;
|
|
if ($request->timeTo && $wpTime > $request->timeTo)
|
|
return false;
|
|
return true;
|
|
})->values();
|
|
}
|
|
|
|
return [
|
|
'id' => (string) $route->id,
|
|
'salesId' => $route->user->employee_id,
|
|
'salesName' => $route->user->name,
|
|
'salesColor' => $route->user->color,
|
|
'date' => $route->date->format('Y-m-d'),
|
|
'waypoints' => $waypoints->map(function ($wp) {
|
|
return [
|
|
'lat' => (float) $wp->latitude,
|
|
'lng' => (float) $wp->longitude,
|
|
'time' => Carbon::parse($wp->recorded_at)->format('H:i'),
|
|
'location' => $wp->location_name ?? 'GPS Point',
|
|
'type' => $wp->type,
|
|
];
|
|
})->values(),
|
|
];
|
|
})->filter(fn($route) => count($route['waypoints']) > 0)->values();
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'summary' => [
|
|
'totalRoutes' => $formattedRoutes->count(),
|
|
'dateRange' => $request->date ?? 'all',
|
|
'timeRange' => ($request->timeFrom || $request->timeTo)
|
|
? ($request->timeFrom ?? '00:00') . ' - ' . ($request->timeTo ?? '23:59')
|
|
: 'all',
|
|
],
|
|
'routes' => $formattedRoutes,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* GET /api/sales-routes/dates
|
|
* Get available dates
|
|
*/
|
|
public function dates(): JsonResponse
|
|
{
|
|
// MongoDB Aggregation to get unique dates
|
|
$rawDates = SalesRoute::raw(function ($collection) {
|
|
return $collection->aggregate([
|
|
[
|
|
'$project' => [
|
|
'dateOnly' => ['$dateToString' => ['format' => '%Y-%m-%d', 'date' => '$date']]
|
|
]
|
|
],
|
|
[
|
|
'$group' => [
|
|
'_id' => '$dateOnly'
|
|
]
|
|
],
|
|
[
|
|
'$sort' => ['_id' => -1]
|
|
]
|
|
]);
|
|
});
|
|
|
|
$dates = collect($rawDates)->map(function ($item) {
|
|
return $item['_id'];
|
|
})->values();
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'dates' => $dates,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* GET /api/sales-routes/sales
|
|
* Get sales list
|
|
*/
|
|
public function sales(): JsonResponse
|
|
{
|
|
$users = User::where('is_active', true)
|
|
->where('role', 'sales')
|
|
->get(['id', 'employee_id', 'name', 'color']);
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'salesList' => $users->map(fn($u) => [
|
|
'id' => $u->employee_id,
|
|
'name' => $u->name,
|
|
'color' => $u->color,
|
|
]),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* GET /api/sales-routes/{id}
|
|
* Get single route
|
|
*/
|
|
public function show(string $id): JsonResponse
|
|
{
|
|
$route = SalesRoute::with(['user:id,employee_id,name,color', 'waypoints'])->find($id);
|
|
|
|
if (!$route) {
|
|
return response()->json(['success' => false, 'error' => 'Route not found'], 404);
|
|
}
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'route' => [
|
|
'id' => (string) $route->id,
|
|
'salesId' => $route->user->employee_id,
|
|
'salesName' => $route->user->name,
|
|
'salesColor' => $route->user->color,
|
|
'date' => $route->date->format('Y-m-d'),
|
|
'waypoints' => $route->waypoints->map(function ($wp) {
|
|
return [
|
|
'lat' => (float) $wp->latitude,
|
|
'lng' => (float) $wp->longitude,
|
|
'time' => Carbon::parse($wp->recorded_at)->format('H:i'),
|
|
'location' => $wp->location_name ?? 'GPS Point',
|
|
'type' => $wp->type,
|
|
];
|
|
}),
|
|
],
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* POST /api/sales-routes/waypoints
|
|
* Create waypoint (for mobile app)
|
|
*/
|
|
public function storeWaypoint(Request $request): JsonResponse
|
|
{
|
|
$request->validate([
|
|
'user_id' => 'required|string',
|
|
'type' => 'required|in:checkin,checkout,gps,lunch,visit',
|
|
'latitude' => 'required|numeric',
|
|
'longitude' => 'required|numeric',
|
|
]);
|
|
|
|
// Find user
|
|
$user = User::where('employee_id', $request->user_id)->first();
|
|
if (!$user) {
|
|
return response()->json(['success' => false, 'error' => 'User not found'], 404);
|
|
}
|
|
|
|
// Get or create today's route
|
|
$today = Carbon::today();
|
|
$route = SalesRoute::firstOrCreate(
|
|
['user_id' => $user->id, 'date' => $today],
|
|
['status' => 'active', 'started_at' => now()]
|
|
);
|
|
|
|
// Create waypoint
|
|
$waypoint = Waypoint::create([
|
|
'sales_route_id' => $route->id,
|
|
'type' => $request->type,
|
|
'latitude' => $request->latitude,
|
|
'longitude' => $request->longitude,
|
|
'recorded_at' => now(),
|
|
'location_name' => $request->location_name,
|
|
'address' => $request->address,
|
|
'notes' => $request->notes,
|
|
'photo_url' => $request->photo_url,
|
|
]);
|
|
|
|
// If checkout, update route status
|
|
if ($request->type === 'checkout') {
|
|
$waypoints = $route->waypoints()->get()->toArray();
|
|
$totalDistance = GeoHelper::calculateRouteDistance($waypoints);
|
|
|
|
$firstWp = $route->waypoints()->orderBy('recorded_at')->first();
|
|
$durationMinutes = $firstWp ? now()->diffInMinutes($firstWp->recorded_at) : 0;
|
|
$visitCount = $route->waypoints()->where('type', 'visit')->count();
|
|
|
|
$route->update([
|
|
'status' => 'completed',
|
|
'ended_at' => now(),
|
|
'total_distance_km' => $totalDistance,
|
|
'total_distance_km' => $totalDistance,
|
|
'total_duration_minutes' => $durationMinutes,
|
|
'total_visits' => $visitCount,
|
|
]);
|
|
|
|
// Save to Sales Link Summary
|
|
SalesRouteSummary::create([
|
|
'user_id' => $user->id,
|
|
'sales_route_id' => $route->id,
|
|
'date' => $today,
|
|
'total_distance_km' => $totalDistance,
|
|
'total_duration_minutes' => $durationMinutes,
|
|
'total_visits' => $visitCount,
|
|
'started_at' => $route->started_at,
|
|
'ended_at' => now(),
|
|
]);
|
|
}
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'data' => [
|
|
'id' => $waypoint->id,
|
|
'sales_route_id' => $route->id,
|
|
'type' => $waypoint->type,
|
|
'latitude' => $waypoint->latitude,
|
|
'longitude' => $waypoint->longitude,
|
|
'recorded_at' => $waypoint->recorded_at,
|
|
'location_name' => $waypoint->location_name,
|
|
],
|
|
'message' => 'Waypoint recorded successfully',
|
|
]);
|
|
}
|
|
|
|
// ============================================================
|
|
// MOBILE API ENDPOINTS (For Flutter App)
|
|
// ============================================================
|
|
|
|
/**
|
|
* POST /api/mobile/login
|
|
* Authenticate user and return settings + profile
|
|
*/
|
|
public function mobileLogin(Request $request): JsonResponse
|
|
{
|
|
$request->validate([
|
|
'username' => 'required|string',
|
|
'password' => 'required',
|
|
]);
|
|
|
|
// Login supports both email and employee_id (username) - case insensitive
|
|
$username = strtolower($request->username);
|
|
|
|
// Find user by email or employee_id
|
|
$user = User::where('email', $username)
|
|
->orWhere('employee_id', $username)
|
|
->first();
|
|
|
|
// Check password (Hash or plain text for legacy/demo)
|
|
if (!$user) {
|
|
return response()->json(['success' => false, 'error' => 'Invalid credentials'], 401);
|
|
}
|
|
|
|
// 1. Check Hashed Password (New Standard)
|
|
if (Hash::check($request->password, $user->password)) {
|
|
// Valid
|
|
}
|
|
// 2. Fallback: Check hardcoded 'password' for demo users who haven't changed pass yet
|
|
// OR check plain text match if DB seeded with plain text
|
|
else if ($request->password === 'password' || $request->password === $user->password) {
|
|
// Valid (Legacy/Demo) - You might want to auto-hash it here if you want to migrate
|
|
} else {
|
|
return response()->json(['success' => false, 'error' => 'Invalid credentials'], 401);
|
|
}
|
|
|
|
if (!$user) {
|
|
return response()->json(['success' => false, 'error' => 'Invalid credentials'], 401);
|
|
}
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'user' => [
|
|
'id' => (string) $user->id,
|
|
'employee_id' => $user->employee_id,
|
|
'name' => $user->name,
|
|
'email' => $user->email,
|
|
'role' => $user->role,
|
|
'color' => $user->color,
|
|
],
|
|
'company' => [
|
|
'name' => 'GeoReach Intelligence',
|
|
'address' => 'Jakarta, Indonesia',
|
|
'logo_url' => 'assets/logo.png',
|
|
],
|
|
'settings' => [
|
|
'local_storage_interval_seconds' => 300, // 5 minutes (Save to local)
|
|
'server_sync_interval_seconds' => 1800, // 30 minutes (Submit to server)
|
|
'gps_accuracy_filter_meters' => 50,
|
|
],
|
|
'message' => 'Login successful',
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* POST /api/mobile/checkin
|
|
* Clock in / start tracking for today
|
|
*/
|
|
public function mobileCheckin(Request $request): JsonResponse
|
|
{
|
|
$request->validate([
|
|
'user_id' => 'required|string',
|
|
'latitude' => 'required|numeric',
|
|
'longitude' => 'required|numeric',
|
|
]);
|
|
|
|
// Find user
|
|
$user = User::where('employee_id', $request->user_id)->first();
|
|
if (!$user) {
|
|
return response()->json(['success' => false, 'error' => 'User not found'], 404);
|
|
}
|
|
|
|
$today = Carbon::today();
|
|
|
|
// Check if already checked in today
|
|
$existingRoute = SalesRoute::where('user_id', $user->id)
|
|
->whereDate('date', $today)
|
|
->first();
|
|
|
|
if ($existingRoute && $existingRoute->status === 'active') {
|
|
return response()->json([
|
|
'success' => false,
|
|
'error' => 'Already checked in today',
|
|
'route_id' => $existingRoute->id,
|
|
], 409);
|
|
}
|
|
|
|
// Create new route for today
|
|
$route = SalesRoute::create([
|
|
'user_id' => $user->id,
|
|
'date' => $today,
|
|
'status' => 'active',
|
|
'started_at' => now(),
|
|
]);
|
|
|
|
// Create check-in waypoint
|
|
Waypoint::create([
|
|
'sales_route_id' => $route->id,
|
|
'type' => 'checkin',
|
|
'latitude' => $request->latitude,
|
|
'longitude' => $request->longitude,
|
|
'recorded_at' => now(),
|
|
'location_name' => $request->location_name ?? 'Check-in Point',
|
|
'notes' => $request->device_info,
|
|
]);
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'route_id' => $route->id,
|
|
'checked_in_at' => now()->format('Y-m-d H:i:s'),
|
|
'message' => 'Check-in successful',
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* POST /api/mobile/checkout
|
|
* Clock out / stop tracking
|
|
*/
|
|
public function mobileCheckout(Request $request): JsonResponse
|
|
{
|
|
$request->validate([
|
|
'user_id' => 'required|string',
|
|
'latitude' => 'required|numeric',
|
|
'longitude' => 'required|numeric',
|
|
]);
|
|
|
|
// Find user
|
|
$user = User::where('employee_id', $request->user_id)->first();
|
|
if (!$user) {
|
|
return response()->json(['success' => false, 'error' => 'User not found'], 404);
|
|
}
|
|
|
|
$today = Carbon::today();
|
|
|
|
// Find active route (from today or previous days)
|
|
$route = SalesRoute::where('user_id', $user->id)
|
|
->where('status', 'active')
|
|
->orderBy('date', 'desc') // Get latest if multiple?
|
|
->first();
|
|
|
|
if (!$route) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'error' => 'No active route found. Please check-in first. (User: ' . $user->employee_id . ')',
|
|
], 400);
|
|
}
|
|
|
|
// Create checkout waypoint
|
|
Waypoint::create([
|
|
'sales_route_id' => $route->id,
|
|
'type' => 'checkout',
|
|
'latitude' => $request->latitude,
|
|
'longitude' => $request->longitude,
|
|
'recorded_at' => now(),
|
|
'location_name' => $request->location_name ?? 'Check-out Point',
|
|
]);
|
|
|
|
// Calculate totals
|
|
$waypoints = $route->waypoints()->get()->toArray();
|
|
$totalDistance = GeoHelper::calculateRouteDistance($waypoints);
|
|
$firstWp = $route->waypoints()->orderBy('recorded_at')->first();
|
|
$durationMinutes = $firstWp ? now()->diffInMinutes($firstWp->recorded_at) : 0;
|
|
$visitCount = $route->waypoints()->where('type', 'visit')->count();
|
|
|
|
// Update route status
|
|
$route->update([
|
|
'status' => 'completed',
|
|
'ended_at' => now(),
|
|
'total_distance_km' => $totalDistance,
|
|
'total_duration_minutes' => $durationMinutes,
|
|
'total_visits' => $visitCount,
|
|
]);
|
|
|
|
// Save to Sales Link Summary
|
|
SalesRouteSummary::create([
|
|
'user_id' => $user->id,
|
|
'sales_route_id' => $route->id,
|
|
'date' => $today,
|
|
'total_distance_km' => $totalDistance,
|
|
'total_duration_minutes' => $durationMinutes,
|
|
'total_visits' => $visitCount,
|
|
'started_at' => $route->started_at,
|
|
'ended_at' => now(),
|
|
]);
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Check-out successful',
|
|
'summary' => [
|
|
'route_id' => $route->id,
|
|
'total_distance_km' => $totalDistance,
|
|
'total_duration_minutes' => $durationMinutes,
|
|
'total_visits' => $visitCount,
|
|
'waypoints_count' => count($waypoints),
|
|
'checked_out_at' => now()->format('Y-m-d H:i:s'),
|
|
],
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* POST /api/mobile/waypoints/batch
|
|
* Batch submit waypoints (for offline support)
|
|
*/
|
|
public function storeBatchWaypoints(Request $request): JsonResponse
|
|
{
|
|
$request->validate([
|
|
'user_id' => 'required|string',
|
|
'waypoints' => 'required|array|min:1',
|
|
'waypoints.*.type' => 'required|in:gps,visit,lunch,checkin,checkout',
|
|
'waypoints.*.latitude' => 'required|numeric',
|
|
'waypoints.*.longitude' => 'required|numeric',
|
|
]);
|
|
|
|
// Find user
|
|
$user = User::where('employee_id', $request->user_id)->first();
|
|
if (!$user) {
|
|
return response()->json(['success' => false, 'error' => 'User not found'], 404);
|
|
}
|
|
|
|
$today = Carbon::today();
|
|
|
|
// Get or create today's route
|
|
$route = SalesRoute::firstOrCreate(
|
|
['user_id' => $user->id, 'date' => $today],
|
|
['status' => 'active', 'started_at' => now()]
|
|
);
|
|
|
|
$inserted = 0;
|
|
|
|
foreach ($request->waypoints as $wp) {
|
|
Waypoint::create([
|
|
'sales_route_id' => $route->id,
|
|
'type' => $wp['type'],
|
|
'latitude' => $wp['latitude'],
|
|
'longitude' => $wp['longitude'],
|
|
'recorded_at' => isset($wp['recorded_at']) ? Carbon::parse($wp['recorded_at']) : now(),
|
|
'location_name' => $wp['location_name'] ?? null,
|
|
'address' => $wp['address'] ?? null,
|
|
'notes' => $wp['notes'] ?? null,
|
|
'photo_url' => $wp['photo_url'] ?? null,
|
|
]);
|
|
$inserted++;
|
|
}
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'inserted' => $inserted,
|
|
'route_id' => $route->id,
|
|
'message' => "{$inserted} waypoints recorded successfully",
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* GET /api/mobile/route/today
|
|
* Get today's route for user
|
|
*/
|
|
public function getTodayRoute(Request $request): JsonResponse
|
|
{
|
|
$request->validate([
|
|
'user_id' => 'required|string',
|
|
]);
|
|
|
|
// Find user
|
|
$user = User::where('employee_id', $request->user_id)->first();
|
|
if (!$user) {
|
|
return response()->json(['success' => false, 'error' => 'User not found'], 404);
|
|
}
|
|
|
|
$today = Carbon::today();
|
|
|
|
$route = SalesRoute::with('waypoints')
|
|
->where('user_id', $user->id)
|
|
->whereDate('date', $today)
|
|
->first();
|
|
|
|
if (!$route) {
|
|
return response()->json([
|
|
'success' => true,
|
|
'route' => null,
|
|
'message' => 'No route found for today',
|
|
]);
|
|
}
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'route' => [
|
|
'id' => $route->id,
|
|
'date' => $route->date->format('Y-m-d'),
|
|
'status' => $route->status,
|
|
'started_at' => $route->started_at?->format('Y-m-d H:i:s'),
|
|
'ended_at' => $route->ended_at?->format('Y-m-d H:i:s'),
|
|
'total_distance_km' => $route->total_distance_km,
|
|
'total_duration_minutes' => $route->total_duration_minutes,
|
|
'waypoints' => $route->waypoints->map(fn($wp) => [
|
|
'id' => $wp->id,
|
|
'type' => $wp->type,
|
|
'lat' => (float) $wp->latitude,
|
|
'lng' => (float) $wp->longitude,
|
|
'time' => Carbon::parse($wp->recorded_at)->format('Y-m-d H:i:s'),
|
|
'location' => $wp->location_name ?? 'GPS Point',
|
|
'notes' => $wp->notes,
|
|
]),
|
|
],
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* GET /api/mobile/status
|
|
* Get current tracking status for user
|
|
*/
|
|
public function getTrackingStatus(Request $request): JsonResponse
|
|
{
|
|
$request->validate([
|
|
'user_id' => 'required|string',
|
|
]);
|
|
|
|
// Find user
|
|
$user = User::where('employee_id', $request->user_id)->first();
|
|
if (!$user) {
|
|
return response()->json(['success' => false, 'error' => 'User not found'], 404);
|
|
}
|
|
|
|
$today = Carbon::today();
|
|
|
|
// MongoDB compatible: get route without withCount
|
|
$route = SalesRoute::where('user_id', $user->id)
|
|
->whereDate('date', $today)
|
|
->first();
|
|
|
|
if (!$route) {
|
|
return response()->json([
|
|
'success' => true,
|
|
'is_checked_in' => false,
|
|
'route_id' => null,
|
|
'checked_in_at' => null,
|
|
'waypoints_today' => 0,
|
|
]);
|
|
}
|
|
|
|
// Count waypoints manually for MongoDB compatibility
|
|
$waypointsCount = $route->waypoints()->count();
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'is_checked_in' => $route->status === 'active',
|
|
'is_completed' => $route->status === 'completed',
|
|
'route_id' => $route->id,
|
|
'checked_in_at' => $route->started_at?->format('Y-m-d H:i:s'),
|
|
'checked_out_at' => $route->ended_at?->format('Y-m-d H:i:s'),
|
|
'waypoints_today' => $waypointsCount,
|
|
'total_distance_km' => $route->total_distance_km,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* POST /api/mobile/profile
|
|
* Update user profile
|
|
*/
|
|
public function updateProfile(Request $request): JsonResponse
|
|
{
|
|
$request->validate([
|
|
'user_id' => 'required|string', // Employee ID or User ID
|
|
'name' => 'sometimes|string',
|
|
'email' => 'sometimes|email',
|
|
'phone' => 'sometimes|string',
|
|
]);
|
|
|
|
$user = User::where('employee_id', $request->user_id)->orWhere('id', $request->user_id)->first();
|
|
if (!$user) {
|
|
return response()->json(['success' => false, 'error' => 'User not found'], 404);
|
|
}
|
|
|
|
if ($request->has('name'))
|
|
$user->name = $request->name;
|
|
if ($request->has('email'))
|
|
$user->email = $request->email;
|
|
if ($request->has('phone'))
|
|
$user->phone = $request->phone;
|
|
|
|
$user->save();
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Profile updated successfully',
|
|
'user' => [
|
|
'id' => (string) $user->id,
|
|
'employee_id' => $user->employee_id,
|
|
'name' => $user->name,
|
|
'email' => $user->email,
|
|
'phone' => $user->phone,
|
|
'role' => $user->role,
|
|
'color' => $user->color,
|
|
],
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* POST /api/mobile/change-password
|
|
* Change user password
|
|
*/
|
|
public function changePassword(Request $request): JsonResponse
|
|
{
|
|
$request->validate([
|
|
'user_id' => 'required|string',
|
|
'current_password' => 'required',
|
|
'new_password' => 'required|min:8', // Add regex if strict is needed
|
|
]);
|
|
|
|
$user = User::where('employee_id', $request->user_id)->orWhere('id', $request->user_id)->first();
|
|
if (!$user) {
|
|
return response()->json(['success' => false, 'error' => 'User not found'], 404);
|
|
}
|
|
|
|
// Verify current password
|
|
// Check hash OR Check basic 'password' fallback
|
|
$isValidCurrent = Hash::check($request->current_password, $user->password)
|
|
|| ($request->current_password === 'password' && !$user->password) // If initial state
|
|
|| $request->current_password === $user->password;
|
|
|
|
if (!$isValidCurrent) {
|
|
return response()->json(['success' => false, 'error' => 'Password lama salah'], 401);
|
|
}
|
|
|
|
// Update to new hashed password
|
|
$user->password = Hash::make($request->new_password);
|
|
$user->save();
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Password berhasil diubah',
|
|
]);
|
|
}
|
|
}
|