orders = new Orders(); $this->topups = new TopupModel(); $this->wallets = new CustomerWallet(); $this->vouchers = new CustomerVoucherList(); $this->points = new CustomerPoint(); $this->checkins = new LogCustomerCheckin(); // Initialize checkins model } public function show($customerId = null) { if (!$customerId) { return $this->fail('Customer ID is required', 400); } $orderSummary = $this->orders ->select('customer_id, COUNT(id) as total_orders, SUM(grand_total) as total_grand') ->where('customer_id', $customerId) ->groupBy('customer_id') ->first(); $topupSummary = $this->topups ->select('customer_id, COUNT(id) as total_topups, SUM(amount) as total_topup_amount') ->where('customer_id', $customerId) ->groupBy('customer_id') ->first(); $pointsSummary = $this->points ->select('customer_id, COUNT(id) as total_point_transactions, SUM(`in`) as total_point_in, SUM(`out`) as total_point_out, MAX(balance) as current_points') ->where('customer_id', $customerId) ->groupBy('customer_id') ->first(); $walletSummary = $this->wallets ->select('customer_id, SUM(`in`) as total_in, SUM(`out`) as total_out, MAX(balance) as current_balance') ->where('customer_id', $customerId) ->groupBy('customer_id') ->first(); $voucherSummary = $this->vouchers ->select('customer_id, COUNT(id) as total_vouchers, SUM(CASE WHEN voucher_status = "active" THEN 1 ELSE 0 END) as active_vouchers, SUM(CASE WHEN voucher_status = "used" THEN 1 ELSE 0 END) as used_vouchers, SUM(CASE WHEN voucher_status = "expired" THEN 1 ELSE 0 END) as expired_vouchers') ->where('customer_id', $customerId) ->groupBy('customer_id') ->first(); $activeVouchers = $this->vouchers ->where('customer_id', $customerId) ->where('voucher_status', 'active') ->where('voucher_expiry_date >=', date('Y-m-d H:i:s')) ->orderBy('voucher_expiry_date', 'ASC') ->findAll(); // Get check-in data $checkinData = $this->checkins ->select('customer_id, COUNT(id) as total_checkins, MAX(streak_count) as highest_streak, MAX(checkin_date) as last_checkin_date') ->where('customer_id', $customerId) ->groupBy('customer_id') ->first(); $recentCheckins = $this->checkins ->where('customer_id', $customerId) ->orderBy('checkin_date', 'DESC') ->limit(7) // Get last 7 check-ins ->findAll(); $orderLifecycle = $this->orders ->select('MIN(created_at) as first_order_date, MAX(created_at) as last_order_date') ->where('customer_id', $customerId) ->where('status !=', 'cancelled') ->first(); $topupLifecycle = $this->topups ->select('MIN(created_at) as first_topup_date, MAX(created_at) as last_topup_date') ->where('customer_id', $customerId) ->where('status', 'success') ->first(); $pointsLifecycle = $this->points ->select('MIN(created_at) as first_point_date, MAX(created_at) as last_point_date') ->where('customer_id', $customerId) ->first(); // Get check-in lifecycle $checkinLifecycle = $this->checkins ->select('MIN(checkin_date) as first_checkin_date, MAX(checkin_date) as last_checkin_date') ->where('customer_id', $customerId) ->first(); $customerStatus = $this->calculateCustomerStatus($orderLifecycle, $topupLifecycle, $pointsLifecycle, $checkinLifecycle); $lifecycleData = [ 'first_activity' => $this->getEarliestDate([ $orderLifecycle['first_order_date'] ?? null, $topupLifecycle['first_topup_date'] ?? null, $pointsLifecycle['first_point_date'] ?? null, $checkinLifecycle['first_checkin_date'] ?? null ]), 'last_activity' => $this->getLatestDate([ $orderLifecycle['last_order_date'] ?? null, $topupLifecycle['last_topup_date'] ?? null, $pointsLifecycle['last_point_date'] ?? null, $checkinLifecycle['last_checkin_date'] ?? null ]), 'first_order' => $orderLifecycle['first_order_date'] ?? null, 'last_order' => $orderLifecycle['last_order_date'] ?? null, 'first_topup' => $topupLifecycle['first_topup_date'] ?? null, 'last_topup' => $topupLifecycle['last_topup_date'] ?? null, 'first_point' => $pointsLifecycle['first_point_date'] ?? null, 'last_point' => $pointsLifecycle['last_point_date'] ?? null, 'first_checkin' => $checkinLifecycle['first_checkin_date'] ?? null, 'last_checkin' => $checkinLifecycle['last_checkin_date'] ?? null, 'customer_status' => $customerStatus, 'days_since_last_activity' => $this->calculateDaysSinceLastActivity( $orderLifecycle['last_order_date'] ?? null, $topupLifecycle['last_topup_date'] ?? null, $pointsLifecycle['last_point_date'] ?? null, $checkinLifecycle['last_checkin_date'] ?? null ) ]; return $this->respond([ 'status' => 200, 'message' => 'Customer dashboard data retrieved successfully', 'data' => [ 'orders' => $orderSummary ?? [ 'customer_id' => $customerId, 'total_orders' => 0, 'total_grand' => 0 ], 'topups' => $topupSummary ?? [ 'customer_id' => $customerId, 'total_topups' => 0, 'total_topup_amount' => 0 ], 'points' => $pointsSummary ?? [ 'customer_id' => $customerId, 'total_point_transactions' => 0, 'total_point_in' => 0, 'total_point_out' => 0, 'current_points' => 0 ], 'wallet' => $walletSummary ?? [ 'customer_id' => $customerId, 'total_in' => 0, 'total_out' => 0, 'current_balance' => 0 ], 'vouchers' => [ 'summary' => $voucherSummary ?? [ 'customer_id' => $customerId, 'total_vouchers' => 0, 'active_vouchers' => 0, 'used_vouchers' => 0, 'expired_vouchers' => 0 ], 'active_vouchers_list' => $activeVouchers ], 'checkins' => [ // Added checkins section 'summary' => $checkinData ?? [ 'customer_id' => $customerId, 'total_checkins' => 0, 'highest_streak' => 0, 'last_checkin_date' => null ], 'recent_checkins' => $recentCheckins ], 'lifecycle' => $lifecycleData ] ]); } private function calculateCustomerStatus($orderLifecycle, $topupLifecycle, $pointsLifecycle, $checkinLifecycle) { $lastOrderDate = $orderLifecycle['last_order_date'] ?? null; $lastTopupDate = $topupLifecycle['last_topup_date'] ?? null; $lastPointDate = $pointsLifecycle['last_point_date'] ?? null; $lastCheckinDate = $checkinLifecycle['last_checkin_date'] ?? null; $lastActivity = $this->getLatestDate([$lastOrderDate, $lastTopupDate, $lastPointDate, $lastCheckinDate]); if (!$lastActivity) { return 'new'; } $daysInactive = $this->calculateDaysSince($lastActivity); if ($daysInactive <= 30) { return 'active'; } elseif ($daysInactive <= 90) { return 'dormant'; } else { return 'churned'; } } private function calculateDaysSinceLastActivity($lastOrderDate, $lastTopupDate, $lastPointDate, $lastCheckinDate) { $lastActivity = $this->getLatestDate([$lastOrderDate, $lastTopupDate, $lastPointDate, $lastCheckinDate]); if (!$lastActivity) { return null; } return $this->calculateDaysSince($lastActivity); } private function calculateDaysSince($dateString) { if (!$dateString) { return null; } $date = new \DateTime($dateString); $now = new \DateTime(); $interval = $now->diff($date); return $interval->days; } private function getEarliestDate(array $dates) { $validDates = array_filter($dates); if (empty($validDates)) { return null; } sort($validDates); return $validDates[0]; } private function getLatestDate(array $dates) { $validDates = array_filter($dates); if (empty($validDates)) { return null; } rsort($validDates); return $validDates[0]; } }