Commit 02bbb1d6 authored by Wei Han's avatar Wei Han

code update

parent 227d7a6d
{
"images" : [
{
"filename" : "star_empty.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "star_full.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
...@@ -17,6 +17,7 @@ NS_ASSUME_NONNULL_BEGIN ...@@ -17,6 +17,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, copy) NSString *drawingPlanId; @property (nonatomic, copy) NSString *drawingPlanId;
@property (nonatomic, copy) NSString *projectLogo; @property (nonatomic, copy) NSString *projectLogo;
@property (nonatomic, copy) NSString *lotId; @property (nonatomic, copy) NSString *lotId;
@property (nonatomic, assign) BOOL canShowSurvey;
@end @end
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#import "APIConfig.h" #import "APIConfig.h"
#import "ImageCacheHelper.h" #import "ImageCacheHelper.h"
#import "ThirdPartyViewController.h" #import "ThirdPartyViewController.h"
#import "SurveyViewController.h"
@interface DashboardViewController () <UIScrollViewDelegate> @interface DashboardViewController () <UIScrollViewDelegate>
...@@ -23,7 +24,6 @@ ...@@ -23,7 +24,6 @@
@property (nonatomic, strong) NSArray *issues; @property (nonatomic, strong) NSArray *issues;
@property (nonatomic, assign) BOOL hasPendingAccess; @property (nonatomic, assign) BOOL hasPendingAccess;
@property (nonatomic, assign) BOOL hasSignOff; @property (nonatomic, assign) BOOL hasSignOff;
@property (nonatomic, strong) NSString *strContactlessHandoverStatus;
@property (nonatomic, strong) NSString *strContactlessFormUrl; @property (nonatomic, strong) NSString *strContactlessFormUrl;
@property (nonatomic, strong) NSString *strPendingAccessReminder; @property (nonatomic, strong) NSString *strPendingAccessReminder;
@property (nonatomic, assign) BOOL bln_Block_Handover; @property (nonatomic, assign) BOOL bln_Block_Handover;
...@@ -48,7 +48,10 @@ ...@@ -48,7 +48,10 @@
@property (nonatomic, strong) UIScrollView *scrollView; @property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UIView *contentView; @property (nonatomic, strong) UIView *contentView;
@property (nonatomic, strong) UIView *stickyBar; @property (nonatomic, strong) UIView *stickyBar;
@property (nonatomic, assign) BOOL hasSubmittedSurvey;
@property (nonatomic, assign) BOOL shouldShowSurveyBanner;
@property (nonatomic, assign) NSDictionary *generalInfo;
@property (nonatomic, strong) NSString *handoverStatus;
@end @end
...@@ -94,6 +97,7 @@ ...@@ -94,6 +97,7 @@
- (void)refreshDashboardContent { - (void)refreshDashboardContent {
NSLog(@"🔁 Refreshing dashboard content..."); NSLog(@"🔁 Refreshing dashboard content...");
[self requestGeneralInfo];
dispatch_group_t group = dispatch_group_create(); dispatch_group_t group = dispatch_group_create();
__block NSDictionary *dashboardData = nil; __block NSDictionary *dashboardData = nil;
__block NSDictionary *announcementData = nil; __block NSDictionary *announcementData = nil;
...@@ -665,12 +669,19 @@ ...@@ -665,12 +669,19 @@
return; return;
} }
NSNumber *surveySubmission = mainData[@"survey_submission"];
BOOL hasSubmittedSurvey = NO;
if (surveySubmission && surveySubmission.intValue == 1) {
hasSubmittedSurvey = YES;
}
self.hasSubmittedSurvey = hasSubmittedSurvey;
NSArray *appointments = mainData[@"appointment"] ?: @[]; NSArray *appointments = mainData[@"appointment"] ?: @[];
NSArray *issues = mainData[@"issue_update"] ?: @[]; NSArray *issues = mainData[@"issue_update"] ?: @[];
NSNumber *paCount = mainData[@"pa_count"]; NSNumber *paCount = mainData[@"pa_count"];
NSNumber *poaCount = mainData[@"poa_count"]; NSNumber *poaCount = mainData[@"poa_count"];
NSString *accessMessage = mainData[@"access_item_message"]; NSString *accessMessage = mainData[@"access_item_message"];
NSString *handoverStatus = mainData[@"contactlessHandoverTempStatus"];
NSString *handoverURL = mainData[@"contactlessHandoverTempURL"]; NSString *handoverURL = mainData[@"contactlessHandoverTempURL"];
BOOL hasPendingAccess = (paCount && paCount.intValue > 0); BOOL hasPendingAccess = (paCount && paCount.intValue > 0);
...@@ -710,7 +721,6 @@ ...@@ -710,7 +721,6 @@
self.bln_Block_Handover = blockHandover; self.bln_Block_Handover = blockHandover;
self.bln_Block_Inspection = blockInspection; self.bln_Block_Inspection = blockInspection;
self.strPendingAccessReminder = accessMessage ?: @""; self.strPendingAccessReminder = accessMessage ?: @"";
self.strContactlessHandoverStatus = handoverStatus ?: @"";
self.strContactlessFormUrl = handoverURL ?: @""; self.strContactlessFormUrl = handoverURL ?: @"";
NSLog(@"✅ Dashboard parsed:"); NSLog(@"✅ Dashboard parsed:");
...@@ -773,6 +783,18 @@ ...@@ -773,6 +783,18 @@
[view removeFromSuperview]; [view removeFromSuperview];
} }
// === Handover Survey ===
if ([self shouldDisplaySurvey]) {
NSLog(@"Displaying Survey");
UIView *surveyRow = [self buildSurveyRow];
[self.contentContainer addArrangedSubview:surveyRow];
[NSLayoutConstraint activateConstraints:@[
[surveyRow.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:16],
[surveyRow.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-16],
]];
}
// === PROJECT UPDATES === // === PROJECT UPDATES ===
NSArray *announcements = self.announcements; NSArray *announcements = self.announcements;
if (announcements.count > 0) { if (announcements.count > 0) {
...@@ -806,6 +828,24 @@ ...@@ -806,6 +828,24 @@
[self.contentContainer addArrangedSubview:bottomSpacer]; [self.contentContainer addArrangedSubview:bottomSpacer];
} }
- (void)requestGeneralInfo{
[APIClient requestGeneralInfo:^(BOOL success, NSDictionary *data, NSError *error) {
if (error || !data) {
NSLog(@"❌ General info error: %@", error.localizedDescription);
return;
}
NSString *plainText = [NSString stringWithFormat:@"%@", data];
NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString *filePath = [docsPath stringByAppendingPathComponent:@"generalData.txt"];
[plainText writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
NSLog(@"📁 appointData saved as plain text to: %@", filePath);
self.handoverStatus = data[@"Data"][@"handover_status"];
self.generalInfo = data;
}];
}
#pragma mark - Announcement Section #pragma mark - Announcement Section
- (UIView *)buildAnnouncementSection:(NSArray *)announcements { - (UIView *)buildAnnouncementSection:(NSArray *)announcements {
UIView *section = [[UIView alloc] init]; UIView *section = [[UIView alloc] init];
...@@ -1519,6 +1559,7 @@ ...@@ -1519,6 +1559,7 @@
nextVC.modalPresentationStyle = UIModalPresentationFullScreen; nextVC.modalPresentationStyle = UIModalPresentationFullScreen;
nextVC.unitID = self.projectCode; nextVC.unitID = self.projectCode;
nextVC.unitName = self.projectName; nextVC.unitName = self.projectName;
nextVC.data = self.generalInfo;
[self presentViewController:nextVC animated:YES completion:nil]; [self presentViewController:nextVC animated:YES completion:nil];
} }
...@@ -1657,4 +1698,79 @@ ...@@ -1657,4 +1698,79 @@
compatibleWithTraitCollection:nil]; compatibleWithTraitCollection:nil];
} }
- (BOOL)shouldDisplaySurvey {
BOOL handedOver =
[self.handoverStatus.lowercaseString isEqualToString:@"handed over"];
return self.canShowSurvey &&
!self.hasSubmittedSurvey &&
handedOver;
}
- (UIView *)buildSurveyRow {
UIView *row = [[UIView alloc] init];
row.translatesAutoresizingMaskIntoConstraints = NO;
row.backgroundColor =
[UIColor colorWithRed:255.0/255.0
green:100.0/255.0
blue:100.0/255.0
alpha:1.0];
row.layer.cornerRadius = 12;
row.clipsToBounds = YES;
[row.heightAnchor constraintEqualToConstant:56].active = YES;
// Tap
UITapGestureRecognizer *tap =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(handleSurveyTap)];
[row addGestureRecognizer:tap];
// Icon
UIImageView *icon = [[UIImageView alloc]
initWithImage:[UIImage imageNamed:@"poa_icon_white"]];
icon.translatesAutoresizingMaskIntoConstraints = NO;
icon.contentMode = UIViewContentModeScaleAspectFit;
[row addSubview:icon];
// Title
UILabel *title = [[UILabel alloc] init];
title.translatesAutoresizingMaskIntoConstraints = NO;
title.text = @"Handover Survey";
title.font = [UIFont boldSystemFontOfSize:16];
title.textColor = UIColor.whiteColor;
[row addSubview:title];
// Chevron
UIImageView *arrow = [[UIImageView alloc]
initWithImage:[UIImage systemImageNamed:@"chevron.right"]];
arrow.translatesAutoresizingMaskIntoConstraints = NO;
arrow.tintColor = UIColor.whiteColor;
[row addSubview:arrow];
[NSLayoutConstraint activateConstraints:@[
[icon.leadingAnchor constraintEqualToAnchor:row.leadingAnchor constant:16],
[icon.centerYAnchor constraintEqualToAnchor:row.centerYAnchor],
[icon.widthAnchor constraintEqualToConstant:24],
[icon.heightAnchor constraintEqualToConstant:24],
[title.leadingAnchor constraintEqualToAnchor:icon.trailingAnchor constant:12],
[title.centerYAnchor constraintEqualToAnchor:row.centerYAnchor],
[arrow.trailingAnchor constraintEqualToAnchor:row.trailingAnchor constant:-16],
[arrow.centerYAnchor constraintEqualToAnchor:row.centerYAnchor],
[arrow.widthAnchor constraintEqualToConstant:16],
[arrow.heightAnchor constraintEqualToConstant:16],
]];
return row;
}
- (void)handleSurveyTap {
NSLog(@"📝 Survey tapped");
SurveyViewController *vc = [[SurveyViewController alloc] init];
vc.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:vc animated:YES completion:nil];
}
@end @end
...@@ -6,5 +6,6 @@ ...@@ -6,5 +6,6 @@
@property (nonatomic, strong) NSString *unitID; @property (nonatomic, strong) NSString *unitID;
@property (nonatomic, strong) NSString *unitName; @property (nonatomic, strong) NSString *unitName;
@property (nonatomic, strong) NSDictionary *data;
@end @end
...@@ -85,7 +85,7 @@ typedef struct { ...@@ -85,7 +85,7 @@ typedef struct {
self.documentsContainer.clipsToBounds = YES; self.documentsContainer.clipsToBounds = YES;
self.formsContainer.clipsToBounds = YES; self.formsContainer.clipsToBounds = YES;
[self requestGeneralInfo]; [self handleGeneralInfo];
[self setupTopBar]; [self setupTopBar];
[self setupTabControl]; [self setupTabControl];
[self setupScrollView]; [self setupScrollView];
...@@ -542,22 +542,9 @@ typedef struct { ...@@ -542,22 +542,9 @@ typedef struct {
} }
#pragma mark - api #pragma mark - api
- (void)requestGeneralInfo { - (void)handleGeneralInfo {
[APIClient requestGeneralInfo:^(BOOL success, NSDictionary *data, NSError *error) { NSLog(@"📦 Received General Info Data: %@", self.data);
if (error || !data) { NSDictionary *general = self.data[@"Data"];
NSLog(@"❌ General info error: %@", error.localizedDescription);
return;
}
NSLog(@"📦 Received General Info Data: %@", data);
NSDictionary *general = data[@"Data"];
// 1️⃣ Write to file for debugging (your existing logic)
NSString *plainText = [NSString stringWithFormat:@"%@", data];
NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString *filePath = [docsPath stringByAppendingPathComponent:@"generalData.txt"];
[plainText writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
NSLog(@"📁 appointData saved as plain text to: %@", filePath);
// 2️⃣ Safely extract each field // 2️⃣ Safely extract each field
self.owners = general[@"unit_owner"] ?: @[]; self.owners = general[@"unit_owner"] ?: @[];
...@@ -602,7 +589,6 @@ typedef struct { ...@@ -602,7 +589,6 @@ typedef struct {
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[self refreshUI]; [self refreshUI];
}); });
}];
} }
- (void)refreshUI { - (void)refreshUI {
......
...@@ -276,6 +276,8 @@ didSelectRowAtIndexPath:(NSIndexPath *)indexPath { ...@@ -276,6 +276,8 @@ didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *drawingPlanId = [unit[@"id"] description]; NSString *drawingPlanId = [unit[@"id"] description];
[APIConfig setDrawingPlanId:drawingPlanId]; [APIConfig setDrawingPlanId:drawingPlanId];
NSLog(@"lotid: %@", unit[@"lot_id"]); NSLog(@"lotid: %@", unit[@"lot_id"]);
NSNumber *ownerSurvey = unit[@"owner_survey"];
BOOL canShowSurvey = (ownerSurvey != nil && ownerSurvey.intValue == 1);
NSLog(@"self.projectLogo: %@", self.projectLogo); NSLog(@"self.projectLogo: %@", self.projectLogo);
DashboardViewController *vc = [[DashboardViewController alloc] init]; DashboardViewController *vc = [[DashboardViewController alloc] init];
...@@ -286,6 +288,7 @@ didSelectRowAtIndexPath:(NSIndexPath *)indexPath { ...@@ -286,6 +288,7 @@ didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
vc.drawerController = self.drawerController; vc.drawerController = self.drawerController;
vc.projectLogo = self.projectLogo; vc.projectLogo = self.projectLogo;
vc.lotId = unit[@"lot_id"] ?: @""; vc.lotId = unit[@"lot_id"] ?: @"";
vc.canShowSurvey = canShowSurvey;
vc.modalPresentationStyle = UIModalPresentationFullScreen; vc.modalPresentationStyle = UIModalPresentationFullScreen;
[self.navigationController pushViewController:vc animated:YES]; [self.navigationController pushViewController:vc animated:YES];
} }
......
// OwnerAcceptanceViewController.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface OwnerAcceptanceViewController : UIViewController
@end
NS_ASSUME_NONNULL_END
// OwnerAcceptanceViewController.mm
#import "APIClient.h"
#import "OwnerAcceptanceViewController.h"
@interface OwnerAcceptanceViewController ()
// Header
@property (nonatomic, strong) UIView *headerBar;
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UIButton *backButton;
@end
@implementation OwnerAcceptanceViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = UIColor.whiteColor;
[self setupHeader];
}
#pragma mark - Header
- (void)setupHeader {
UILayoutGuide *safe = self.view.safeAreaLayoutGuide;
self.headerBar = [[UIView alloc] init];
self.headerBar.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0];
self.headerBar.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.headerBar];
[NSLayoutConstraint activateConstraints:@[
[self.headerBar.topAnchor constraintEqualToAnchor:safe.topAnchor],
[self.headerBar.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.headerBar.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.headerBar.heightAnchor constraintEqualToConstant:44],
]];
self.titleLabel = [[UILabel alloc] init];
self.titleLabel.text = @"Handover Survey";
self.titleLabel.font = [UIFont systemFontOfSize:18 weight:UIFontWeightMedium];
self.titleLabel.textColor = UIColor.whiteColor;
self.titleLabel.textAlignment = NSTextAlignmentCenter;
self.backButton = [UIButton buttonWithType:UIButtonTypeSystem];
[self.backButton setImage:[UIImage systemImageNamed:@"chevron.backward"] forState:UIControlStateNormal];
self.backButton.tintColor = UIColor.whiteColor;
[self.backButton addTarget:self action:@selector(onBack) forControlEvents:UIControlEventTouchUpInside];
for (UIView *sub in @[self.titleLabel, self.backButton]) {
sub.translatesAutoresizingMaskIntoConstraints = NO;
[self.headerBar addSubview:sub];
}
[NSLayoutConstraint activateConstraints:@[
[self.backButton.leadingAnchor constraintEqualToAnchor:self.headerBar.leadingAnchor constant:16],
[self.backButton.centerYAnchor constraintEqualToAnchor:self.headerBar.centerYAnchor],
[self.backButton.widthAnchor constraintEqualToConstant:24],
[self.backButton.heightAnchor constraintEqualToConstant:24],
[self.titleLabel.centerXAnchor constraintEqualToAnchor:self.headerBar.centerXAnchor],
[self.titleLabel.centerYAnchor constraintEqualToAnchor:self.headerBar.centerYAnchor],
]];
}
- (void)onBack {
[self dismissViewControllerAnimated:YES completion:nil];
}
@end
// POAViewController.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface POAViewController : UIViewController
@end
NS_ASSUME_NONNULL_END
// POAViewController.mm
#import "APIClient.h"
#import "POAViewController.h"
@interface POAViewController ()
// Header
@property (nonatomic, strong) UIView *headerBar;
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UIButton *backButton;
@end
@implementation POAViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = UIColor.whiteColor;
[self setupHeader];
}
#pragma mark - Header
- (void)setupHeader {
UILayoutGuide *safe = self.view.safeAreaLayoutGuide;
self.headerBar = [[UIView alloc] init];
self.headerBar.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0];
self.headerBar.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.headerBar];
[NSLayoutConstraint activateConstraints:@[
[self.headerBar.topAnchor constraintEqualToAnchor:safe.topAnchor],
[self.headerBar.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.headerBar.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.headerBar.heightAnchor constraintEqualToConstant:44],
]];
self.titleLabel = [[UILabel alloc] init];
self.titleLabel.text = @"Handover Survey";
self.titleLabel.font = [UIFont systemFontOfSize:18 weight:UIFontWeightMedium];
self.titleLabel.textColor = UIColor.whiteColor;
self.titleLabel.textAlignment = NSTextAlignmentCenter;
self.backButton = [UIButton buttonWithType:UIButtonTypeSystem];
[self.backButton setImage:[UIImage systemImageNamed:@"chevron.backward"] forState:UIControlStateNormal];
self.backButton.tintColor = UIColor.whiteColor;
[self.backButton addTarget:self action:@selector(onBack) forControlEvents:UIControlEventTouchUpInside];
for (UIView *sub in @[self.titleLabel, self.backButton]) {
sub.translatesAutoresizingMaskIntoConstraints = NO;
[self.headerBar addSubview:sub];
}
[NSLayoutConstraint activateConstraints:@[
[self.backButton.leadingAnchor constraintEqualToAnchor:self.headerBar.leadingAnchor constant:16],
[self.backButton.centerYAnchor constraintEqualToAnchor:self.headerBar.centerYAnchor],
[self.backButton.widthAnchor constraintEqualToConstant:24],
[self.backButton.heightAnchor constraintEqualToConstant:24],
[self.titleLabel.centerXAnchor constraintEqualToAnchor:self.headerBar.centerXAnchor],
[self.titleLabel.centerYAnchor constraintEqualToAnchor:self.headerBar.centerYAnchor],
]];
}
- (void)onBack {
[self dismissViewControllerAnimated:YES completion:nil];
}
@end
//
// SinglePoaViewController.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface SinglePOAViewController : UIViewController
@end
NS_ASSUME_NONNULL_END
// SinglePoaViewController.mm
#import "APIClient.h"
#import "SinglePOAViewController.h"
@interface SinglePOAViewController ()
// Header
@property (nonatomic, strong) UIView *headerBar;
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UIButton *backButton;
@end
@implementation SinglePOAViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = UIColor.whiteColor;
[self setupHeader];
}
#pragma mark - Header
- (void)setupHeader {
UILayoutGuide *safe = self.view.safeAreaLayoutGuide;
self.headerBar = [[UIView alloc] init];
self.headerBar.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0];
self.headerBar.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.headerBar];
[NSLayoutConstraint activateConstraints:@[
[self.headerBar.topAnchor constraintEqualToAnchor:safe.topAnchor],
[self.headerBar.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.headerBar.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.headerBar.heightAnchor constraintEqualToConstant:44],
]];
self.titleLabel = [[UILabel alloc] init];
self.titleLabel.text = @"Handover Survey";
self.titleLabel.font = [UIFont systemFontOfSize:18 weight:UIFontWeightMedium];
self.titleLabel.textColor = UIColor.whiteColor;
self.titleLabel.textAlignment = NSTextAlignmentCenter;
self.backButton = [UIButton buttonWithType:UIButtonTypeSystem];
[self.backButton setImage:[UIImage systemImageNamed:@"chevron.backward"] forState:UIControlStateNormal];
self.backButton.tintColor = UIColor.whiteColor;
[self.backButton addTarget:self action:@selector(onBack) forControlEvents:UIControlEventTouchUpInside];
for (UIView *sub in @[self.titleLabel, self.backButton]) {
sub.translatesAutoresizingMaskIntoConstraints = NO;
[self.headerBar addSubview:sub];
}
[NSLayoutConstraint activateConstraints:@[
[self.backButton.leadingAnchor constraintEqualToAnchor:self.headerBar.leadingAnchor constant:16],
[self.backButton.centerYAnchor constraintEqualToAnchor:self.headerBar.centerYAnchor],
[self.backButton.widthAnchor constraintEqualToConstant:24],
[self.backButton.heightAnchor constraintEqualToConstant:24],
[self.titleLabel.centerXAnchor constraintEqualToAnchor:self.headerBar.centerXAnchor],
[self.titleLabel.centerYAnchor constraintEqualToAnchor:self.headerBar.centerYAnchor],
]];
}
- (void)onBack {
[self dismissViewControllerAnimated:YES completion:nil];
}
@end
// SurveyViewController.h // SurveyViewController.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface SurveyViewController : UIViewController
@end
NS_ASSUME_NONNULL_END
// SurveyViewController.mm // SurveyViewController.mm
#import "APIClient.h"
#import "SurveyViewController.h"
@interface SurveyViewController ()
// Header
@property (nonatomic, strong) UIView *headerBar;
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UIButton *backButton;
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UIView *contentView;
@property (nonatomic, strong) UIButton *submitButton;
// Survey Components
@property (nonatomic, assign) NSInteger surveyId;
@property (nonatomic, copy) NSString *question;
@property (nonatomic, copy) NSString *type;
@property (nonatomic, copy) NSString *style;
@property (nonatomic, assign) NSInteger numberOfRates;
@property (nonatomic, assign) BOOL mandatory;
@property (nonatomic, strong) NSArray<NSDictionary *> *ratesChecklist;
@property (nonatomic, strong) NSMutableDictionary<NSNumber *, id> *answers;
@end
@implementation SurveyViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = UIColor.whiteColor;
self.answers = [NSMutableDictionary dictionary];
[self setupHeader];
[self setupScrollView];
[self requestSurvey];
}
#pragma mark - Header
- (void)setupHeader {
UILayoutGuide *safe = self.view.safeAreaLayoutGuide;
self.headerBar = [[UIView alloc] init];
self.headerBar.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0];
self.headerBar.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.headerBar];
[NSLayoutConstraint activateConstraints:@[
[self.headerBar.topAnchor constraintEqualToAnchor:safe.topAnchor],
[self.headerBar.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.headerBar.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.headerBar.heightAnchor constraintEqualToConstant:44],
]];
self.titleLabel = [[UILabel alloc] init];
self.titleLabel.text = @"Handover Survey";
self.titleLabel.font = [UIFont systemFontOfSize:18 weight:UIFontWeightMedium];
self.titleLabel.textColor = UIColor.whiteColor;
self.titleLabel.textAlignment = NSTextAlignmentCenter;
self.backButton = [UIButton buttonWithType:UIButtonTypeSystem];
[self.backButton setImage:[UIImage systemImageNamed:@"chevron.backward"] forState:UIControlStateNormal];
self.backButton.tintColor = UIColor.whiteColor;
[self.backButton addTarget:self action:@selector(onBack) forControlEvents:UIControlEventTouchUpInside];
for (UIView *sub in @[self.titleLabel, self.backButton]) {
sub.translatesAutoresizingMaskIntoConstraints = NO;
[self.headerBar addSubview:sub];
}
[NSLayoutConstraint activateConstraints:@[
[self.backButton.leadingAnchor constraintEqualToAnchor:self.headerBar.leadingAnchor constant:16],
[self.backButton.centerYAnchor constraintEqualToAnchor:self.headerBar.centerYAnchor],
[self.backButton.widthAnchor constraintEqualToConstant:24],
[self.backButton.heightAnchor constraintEqualToConstant:24],
[self.titleLabel.centerXAnchor constraintEqualToAnchor:self.headerBar.centerXAnchor],
[self.titleLabel.centerYAnchor constraintEqualToAnchor:self.headerBar.centerYAnchor],
]];
}
- (void)onBack {
[self dismissViewControllerAnimated:YES completion:nil];
}
#pragma mark - Scroll View
- (void)setupScrollView {
UILayoutGuide *safe = self.view.safeAreaLayoutGuide;
self.scrollView = [[UIScrollView alloc] init];
self.scrollView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.scrollView];
[NSLayoutConstraint activateConstraints:@[
[self.scrollView.topAnchor constraintEqualToAnchor:self.headerBar.bottomAnchor],
[self.scrollView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.scrollView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.scrollView.bottomAnchor constraintEqualToAnchor:safe.bottomAnchor],
]];
self.contentView = [[UIView alloc] init];
self.contentView.translatesAutoresizingMaskIntoConstraints = NO;
[self.scrollView addSubview:self.contentView];
[NSLayoutConstraint activateConstraints:@[
[self.contentView.topAnchor constraintEqualToAnchor:self.scrollView.topAnchor],
[self.contentView.leadingAnchor constraintEqualToAnchor:self.scrollView.leadingAnchor],
[self.contentView.trailingAnchor constraintEqualToAnchor:self.scrollView.trailingAnchor],
[self.contentView.bottomAnchor constraintEqualToAnchor:self.scrollView.bottomAnchor],
[self.contentView.widthAnchor constraintEqualToAnchor:self.scrollView.widthAnchor],
]];
}
- (void)renderSurvey:(NSDictionary *)surveyData {
NSArray *sections = surveyData[@"section"];
UIView *previous = nil;
for (NSDictionary *sectionDict in sections) {
NSString *sectionName = sectionDict[@"name"];
// Section Label
UIView *sectionHeader = [[UIView alloc] init];
sectionHeader.backgroundColor = UIColor.blackColor;
sectionHeader.translatesAutoresizingMaskIntoConstraints = NO;
UILabel *sectionLabel = [[UILabel alloc] init];
sectionLabel.text = sectionName;
sectionLabel.textColor = UIColor.whiteColor;
sectionLabel.font = [UIFont systemFontOfSize:16];
sectionLabel.numberOfLines = 0;
sectionLabel.translatesAutoresizingMaskIntoConstraints = NO;
[sectionHeader addSubview:sectionLabel];
[self.contentView addSubview:sectionHeader];
[NSLayoutConstraint activateConstraints:@[
[sectionHeader.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
[sectionHeader.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-16],
previous ?
[sectionHeader.topAnchor constraintEqualToAnchor:previous.bottomAnchor constant:24] :
[sectionHeader.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:24],
[sectionLabel.topAnchor constraintEqualToAnchor:sectionHeader.topAnchor constant:12],
[sectionLabel.bottomAnchor constraintEqualToAnchor:sectionHeader.bottomAnchor constant:-12],
[sectionLabel.leadingAnchor constraintEqualToAnchor:sectionHeader.leadingAnchor constant:12],
[sectionLabel.trailingAnchor constraintEqualToAnchor:sectionHeader.trailingAnchor constant:-12],
]];
previous = sectionLabel;
// Questions
NSArray *surveys = sectionDict[@"survey"];
for (NSDictionary *surveyItem in surveys) {
UIView *questionView = [self buildQuestionView:surveyItem];
[self.contentView addSubview:questionView];
[NSLayoutConstraint activateConstraints:@[
[questionView.topAnchor constraintEqualToAnchor:previous.bottomAnchor constant:16],
[questionView.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
[questionView.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-16],
]];
previous = questionView;
}
}
self.submitButton = [UIButton buttonWithType:UIButtonTypeSystem];
[self.submitButton setTitle:@"Submit" forState:UIControlStateNormal];
self.submitButton.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0];
[self.submitButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
self.submitButton.layer.cornerRadius = 8;
self.submitButton.translatesAutoresizingMaskIntoConstraints = NO;
[self.submitButton addTarget:self action:@selector(onSubmit) forControlEvents:UIControlEventTouchUpInside];
[self.contentView addSubview:self.submitButton];
[NSLayoutConstraint activateConstraints:@[
[self.submitButton.topAnchor constraintEqualToAnchor:previous.bottomAnchor constant:32],
[self.submitButton.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
[self.submitButton.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-16],
[self.submitButton.heightAnchor constraintEqualToConstant:48],
[self.submitButton.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor constant:-32],
]];
}
- (UIView *)buildQuestionView:(NSDictionary *)item {
NSString *type = item[@"type"];
NSString *style = item[@"style"];
if ([type isEqualToString:@"rate"]) {
if ([style isEqualToString:@"number"]) {
return [self buildNumberRating:item];
} else if ([style isEqualToString:@"star"]) {
return [self buildStarRating:item];
}
} else if ([type isEqualToString:@"comment"]) {
return [self buildCommentField:item];
} else if ([type isEqualToString:@"rateNps"]) {
return [self buildNPSRating:item];
} else {
return [self buildQuestionPlaceholder:item];
}
return [self buildQuestionPlaceholder:item];
}
- (UIView *)buildStarRating:(NSDictionary *)item {
UIView *container = [[UIView alloc] init];
container.translatesAutoresizingMaskIntoConstraints = NO;
container.tag = [item[@"id"] integerValue];
// Question
UILabel *label = [[UILabel alloc] init];
label.text = item[@"question"];
label.font = [UIFont systemFontOfSize:14 weight:UIFontWeightBold];
label.numberOfLines = 0;
label.translatesAutoresizingMaskIntoConstraints = NO;
[container addSubview:label];
// Helper
UILabel *helper = [[UILabel alloc] init];
helper.font = [UIFont systemFontOfSize:12];
helper.textColor = UIColor.grayColor;
helper.numberOfLines = 0;
helper.translatesAutoresizingMaskIntoConstraints = NO;
helper.text = [self buildRatesHelperText:item[@"rates_checklist_label"]];
helper.hidden = (helper.text.length == 0);
[container addSubview:helper];
// Stars container
UIView *starsContainer = [[UIView alloc] init];
starsContainer.translatesAutoresizingMaskIntoConstraints = NO;
[container addSubview:starsContainer];
NSInteger rawCount = [item[@"number_of_rates"] integerValue];
NSInteger starCount = MIN(rawCount, 5);
CGFloat size = 32;
CGFloat spacing = 8;
for (int i = 1; i <= starCount; i++) {
UIButton *star = [UIButton buttonWithType:UIButtonTypeCustom];
star.frame = CGRectMake((i - 1) * (size + spacing), 0, size, size);
star.tag = i;
[star setImage:[UIImage imageNamed:@"star_empty"] forState:UIControlStateNormal];
[star addTarget:self
action:@selector(onStarTapped:)
forControlEvents:UIControlEventTouchUpInside];
[starsContainer addSubview:star];
}
CGFloat totalWidth = starCount * size + (starCount - 1) * spacing;
[starsContainer.widthAnchor constraintEqualToConstant:totalWidth].active = YES;
[starsContainer.heightAnchor constraintEqualToConstant:size].active = YES;
// Constraints
[NSLayoutConstraint activateConstraints:@[
[label.topAnchor constraintEqualToAnchor:container.topAnchor],
[label.leadingAnchor constraintEqualToAnchor:container.leadingAnchor],
[label.trailingAnchor constraintEqualToAnchor:container.trailingAnchor],
helper.hidden ?
[starsContainer.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:8] :
[helper.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:6],
[helper.leadingAnchor constraintEqualToAnchor:container.leadingAnchor],
[helper.trailingAnchor constraintEqualToAnchor:container.trailingAnchor],
[starsContainer.topAnchor constraintEqualToAnchor:helper.bottomAnchor constant:8],
[starsContainer.leadingAnchor constraintEqualToAnchor:container.leadingAnchor],
[starsContainer.bottomAnchor constraintEqualToAnchor:container.bottomAnchor],
]];
return container;
}
- (void)onStarTapped:(UIButton *)sender {
UIView *starsContainer = sender.superview;
UIView *questionContainer = starsContainer.superview;
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSInteger selected = sender.tag;
for (UIButton *star in starsContainer.subviews) {
if (star.tag <= selected) {
[star setImage:[UIImage imageNamed:@"star_full" inBundle:bundle compatibleWithTraitCollection:nil]
forState:UIControlStateNormal];
} else {
[star setImage:[UIImage imageNamed:@"star_empty" inBundle:bundle compatibleWithTraitCollection:nil]
forState:UIControlStateNormal];
}
}
NSNumber *questionId = @(questionContainer.tag);
self.answers[questionId] = @(selected);
NSLog(@"⭐ Saved Q%@ = %@", questionId, self.answers[questionId]);
}
- (UIView *)buildCommentField:(NSDictionary *)item {
UIView *container = [[UIView alloc] init];
container.translatesAutoresizingMaskIntoConstraints = NO;
UILabel *label = [[UILabel alloc] init];
label.text = item[@"question"];
label.font = [UIFont systemFontOfSize:14 weight:UIFontWeightBold];
label.translatesAutoresizingMaskIntoConstraints = NO;
[container addSubview:label];
UITextField *textField = [[UITextField alloc] init];
textField.borderStyle = UITextBorderStyleRoundedRect;
textField.translatesAutoresizingMaskIntoConstraints = NO;
[container addSubview:textField];
textField.tag = [item[@"id"] integerValue];
[textField addTarget:self
action:@selector(onCommentChanged:)
forControlEvents:UIControlEventEditingChanged];
[NSLayoutConstraint activateConstraints:@[
[label.topAnchor constraintEqualToAnchor:container.topAnchor],
[label.leadingAnchor constraintEqualToAnchor:container.leadingAnchor],
[label.trailingAnchor constraintEqualToAnchor:container.trailingAnchor],
[textField.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:8],
[textField.leadingAnchor constraintEqualToAnchor:container.leadingAnchor],
[textField.trailingAnchor constraintEqualToAnchor:container.trailingAnchor],
[textField.heightAnchor constraintEqualToConstant:32],
[textField.bottomAnchor constraintEqualToAnchor:container.bottomAnchor],
]];
container.tag = [item[@"id"] integerValue];
return container;
}
- (void)onCommentChanged:(UITextField *)field {
self.answers[@(field.tag)] = field.text ?: @"";
}
- (UIView *)buildNPSRating:(NSDictionary *)item {
UIView *container = [[UIView alloc] init];
container.translatesAutoresizingMaskIntoConstraints = NO;
container.tag = [item[@"id"] integerValue];
// Question
UILabel *label = [[UILabel alloc] init];
label.text = item[@"question"];
label.font = [UIFont systemFontOfSize:14 weight:UIFontWeightBold];
label.numberOfLines = 0;
label.translatesAutoresizingMaskIntoConstraints = NO;
[container addSubview:label];
// Helper
UILabel *helper = [[UILabel alloc] init];
helper.font = [UIFont systemFontOfSize:12];
helper.textColor = UIColor.grayColor;
helper.numberOfLines = 0;
helper.translatesAutoresizingMaskIntoConstraints = NO;
helper.text = [self buildRatesHelperText:item[@"rates_checklist_label"]];
helper.hidden = (helper.text.length == 0);
[container addSubview:helper];
// Buttons container
UIView *buttonsContainer = [[UIView alloc] init];
buttonsContainer.translatesAutoresizingMaskIntoConstraints = NO;
[container addSubview:buttonsContainer];
CGFloat size = 36;
CGFloat spacing = 8;
NSInteger value = 0;
CGFloat x = 0;
CGFloat y = 0;
for (int i = 0; i <= 10; i++) {
// Wrap after 8 → row 2 (9,10)
if (i == 9) {
x = 0;
y += size + spacing;
}
UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem];
btn.frame = CGRectMake(x, y, size, size);
btn.tag = i;
btn.layer.cornerRadius = 6;
btn.backgroundColor = [self npsColorForValue:i selected:NO];
[btn setTitle:[NSString stringWithFormat:@"%d", i] forState:UIControlStateNormal];
[btn setTitleColor:UIColor.blackColor forState:UIControlStateNormal];
[btn addTarget:self
action:@selector(onNPSTapped:)
forControlEvents:UIControlEventTouchUpInside];
[buttonsContainer addSubview:btn];
x += size + spacing;
}
CGFloat totalHeight = y + size;
[buttonsContainer.heightAnchor constraintEqualToConstant:totalHeight].active = YES;
// Constraints
[NSLayoutConstraint activateConstraints:@[
[label.topAnchor constraintEqualToAnchor:container.topAnchor],
[label.leadingAnchor constraintEqualToAnchor:container.leadingAnchor],
[label.trailingAnchor constraintEqualToAnchor:container.trailingAnchor],
helper.hidden ?
[buttonsContainer.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:8] :
[helper.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:6],
[helper.leadingAnchor constraintEqualToAnchor:container.leadingAnchor],
[helper.trailingAnchor constraintEqualToAnchor:container.trailingAnchor],
[buttonsContainer.topAnchor constraintEqualToAnchor:helper.bottomAnchor constant:8],
[buttonsContainer.leadingAnchor constraintEqualToAnchor:container.leadingAnchor],
[buttonsContainer.trailingAnchor constraintEqualToAnchor:container.trailingAnchor],
[buttonsContainer.bottomAnchor constraintEqualToAnchor:container.bottomAnchor],
]];
return container;
}
- (void)onNPSTapped:(UIButton *)sender {
UIView *buttonsContainer = sender.superview;
UIView *questionContainer = buttonsContainer.superview;
NSInteger selected = sender.tag;
for (UIButton *btn in buttonsContainer.subviews) {
BOOL isSelected = (btn.tag == selected);
btn.backgroundColor = [self npsColorForValue:btn.tag selected:isSelected];
[btn setTitleColor:isSelected ? UIColor.whiteColor : UIColor.blackColor
forState:UIControlStateNormal];
}
NSNumber *questionId = @(questionContainer.tag);
self.answers[questionId] = @(selected);
NSLog(@"📊 Saved NPS Q%@ = %@", questionId, self.answers[questionId]);
}
- (UIColor *)npsColorForValue:(NSInteger)value selected:(BOOL)selected {
UIColor *base;
if (value <= 1) {
base = [UIColor colorWithRed:0.86 green:0.23 blue:0.23 alpha:1.0]; // red
} else if (value <= 6) {
base = [UIColor colorWithRed:0.96 green:0.58 blue:0.11 alpha:1.0]; // orange
} else if (value <= 8) {
base = [UIColor colorWithRed:0.96 green:0.79 blue:0.11 alpha:1.0]; // yellow
} else {
base = [UIColor colorWithRed:0.24 green:0.70 blue:0.44 alpha:1.0]; // green
}
return selected ? base : [base colorWithAlphaComponent:0.35];
}
- (UIView *)buildNumberRating:(NSDictionary *)item {
UIView *container = [[UIView alloc] init];
container.translatesAutoresizingMaskIntoConstraints = NO;
container.tag = [item[@"id"] integerValue];
// Question
UILabel *label = [[UILabel alloc] init];
label.text = item[@"question"];
label.font = [UIFont systemFontOfSize:14 weight:UIFontWeightBold];
label.numberOfLines = 0;
label.translatesAutoresizingMaskIntoConstraints = NO;
[container addSubview:label];
// Helper
UILabel *helper = [[UILabel alloc] init];
helper.font = [UIFont systemFontOfSize:12];
helper.textColor = UIColor.grayColor;
helper.numberOfLines = 0;
helper.translatesAutoresizingMaskIntoConstraints = NO;
helper.text = [self buildRatesHelperText:item[@"rates_checklist_label"]];
helper.hidden = (helper.text.length == 0);
[container addSubview:helper];
// Buttons container (wrap layout)
UIView *buttonsContainer = [[UIView alloc] init];
buttonsContainer.translatesAutoresizingMaskIntoConstraints = NO;
[container addSubview:buttonsContainer];
NSInteger count = [item[@"number_of_rates"] integerValue];
CGFloat buttonSize = 40;
CGFloat spacing = 8;
CGFloat maxWidth = UIScreen.mainScreen.bounds.size.width - 32 - 32;
CGFloat x = 0;
CGFloat y = 0;
for (int i = 1; i <= count; i++) {
if (x + buttonSize > maxWidth) {
x = 0;
y += buttonSize + spacing;
}
UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem];
btn.frame = CGRectMake(x, y, buttonSize, buttonSize);
btn.tag = i;
btn.layer.cornerRadius = 6;
btn.layer.borderWidth = 1;
btn.layer.borderColor = UIColor.lightGrayColor.CGColor;
btn.backgroundColor = UIColor.whiteColor;
[btn setTitle:[NSString stringWithFormat:@"%d", i] forState:UIControlStateNormal];
[btn setTitleColor:UIColor.blackColor forState:UIControlStateNormal];
[btn addTarget:self
action:@selector(onNumberTapped:)
forControlEvents:UIControlEventTouchUpInside];
[buttonsContainer addSubview:btn];
x += buttonSize + spacing;
}
CGFloat totalHeight = y + buttonSize;
[buttonsContainer.heightAnchor constraintEqualToConstant:totalHeight].active = YES;
// Constraints
[NSLayoutConstraint activateConstraints:@[
[label.topAnchor constraintEqualToAnchor:container.topAnchor],
[label.leadingAnchor constraintEqualToAnchor:container.leadingAnchor],
[label.trailingAnchor constraintEqualToAnchor:container.trailingAnchor],
helper.hidden ?
[buttonsContainer.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:8] :
[helper.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:6],
[helper.leadingAnchor constraintEqualToAnchor:container.leadingAnchor],
[helper.trailingAnchor constraintEqualToAnchor:container.trailingAnchor],
[buttonsContainer.topAnchor constraintEqualToAnchor:helper.bottomAnchor constant:8],
[buttonsContainer.leadingAnchor constraintEqualToAnchor:container.leadingAnchor],
[buttonsContainer.trailingAnchor constraintEqualToAnchor:container.trailingAnchor],
[buttonsContainer.bottomAnchor constraintEqualToAnchor:container.bottomAnchor],
]];
return container;
}
- (void)onNumberTapped:(UIButton *)sender {
UIView *buttonsContainer = sender.superview;
UIView *questionContainer = buttonsContainer.superview;
// Reset all buttons
for (UIButton *btn in buttonsContainer.subviews) {
btn.backgroundColor = UIColor.whiteColor;
btn.layer.borderColor = UIColor.lightGrayColor.CGColor;
[btn setTitleColor:UIColor.blackColor forState:UIControlStateNormal];
}
// Highlight selected
sender.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0];
sender.layer.borderColor = UIColor.clearColor.CGColor;
[sender setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
NSNumber *questionId = @(questionContainer.tag);
self.answers[questionId] = @(sender.tag);
NSLog(@"🔢 Saved Q%@ = %@", questionId, self.answers[questionId]);
}
- (UIView *)buildQuestionPlaceholder:(NSDictionary *)item {
UIView *container = [[UIView alloc] init];
container.translatesAutoresizingMaskIntoConstraints = NO;
UILabel *label = [[UILabel alloc] init];
label.text = item[@"question"];
label.font = [UIFont systemFontOfSize:14 weight:UIFontWeightBold];
label.translatesAutoresizingMaskIntoConstraints = NO;
[container addSubview:label];
UISegmentedControl *seg = [[UISegmentedControl alloc] initWithItems:@[@"0",@"1",@"2",@"3",@"4",@"5",@"6",@"7",@"8",@"9",@"10"]];
seg.translatesAutoresizingMaskIntoConstraints = NO;
[container addSubview:seg];
[NSLayoutConstraint activateConstraints:@[
[label.topAnchor constraintEqualToAnchor:container.topAnchor],
[label.leadingAnchor constraintEqualToAnchor:container.leadingAnchor],
[label.trailingAnchor constraintEqualToAnchor:container.trailingAnchor],
[seg.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:8],
[seg.leadingAnchor constraintEqualToAnchor:container.leadingAnchor],
[seg.trailingAnchor constraintEqualToAnchor:container.trailingAnchor],
[seg.bottomAnchor constraintEqualToAnchor:container.bottomAnchor],
]];
return container;
}
- (void)onSubmit {
NSLog(@"submit pressed");
// Validate mandatory fields
// for (NSDictionary *section in self.surveyData[@"section"]) {
// for (NSDictionary *q in section[@"survey"]) {
// BOOL mandatory = [q[@"mandatory"] boolValue];
// NSInteger qId = [q[@"id"] integerValue];
// if (mandatory && (!self.answers[@(qId)] ||
// [self.answers[@(qId)] isEqual:@""])) {
// NSLog(@"❌ Question %ld is mandatory", (long)qId);
// return;
// }
// }
// }
//
// // Call API
// [self requestSubmitSurvey];
}
#pragma mark - API
-(void)requestSurvey {
[APIClient requestSurvey:^(BOOL success, NSDictionary * _Nullable data, NSError * _Nullable error) {
// Save debug file
NSString *plainText = [NSString stringWithFormat:@"%@", data];
NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString *filePath = [docsPath stringByAppendingPathComponent:@"survey.txt"];
[plainText writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
NSLog(@"📁 survey saved as plain text to: %@", filePath);
if (error || !data) {
NSLog(@"❌ survey API failed: %@", error);
return;
}
if (data[@"status_code"]) {
NSLog(@"❌ survey status error: %@", data[@"message"]);
return;
}
NSDictionary *appData = data[@"AppData"];
if (![appData[@"status"] isEqualToString:@"success"]) {
NSLog(@"❌ survey failure: %@", appData[@"message"]);
return;
}
NSArray *surveyArray = data[@"Data"];
if (![surveyArray isKindOfClass:[NSArray class]] || surveyArray.count == 0) {
NSLog(@"❌ Invalid notification format");
return;
}
NSDictionary *survey = surveyArray[0]; // First survey object
if (![survey isKindOfClass:[NSDictionary class]]) {
NSLog(@"❌ Invalid survey format");
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
self.surveyId = [survey[@"id"] integerValue];
self.question = survey[@"question"];
self.type = survey[@"type"];
self.style = survey[@"style"];
self.numberOfRates = [survey[@"number_of_rates"] integerValue];
self.mandatory = [survey[@"mandatory"] boolValue];
self.ratesChecklist = survey[@"rates_checklist_label"];
[self renderSurvey:survey];
});
}];
}
- (void)requestSubmitSurvey {
// NSMutableArray *payload = [NSMutableArray array];
// [self.answers enumerateKeysAndObjectsUsingBlock:^(NSNumber *surveyId, id answer, BOOL *stop) {
// [payload addObject:@{@"surveyId": surveyId, @"value": answer}];
// }];
//
// [APIClient submitSurvey:payload completion:^(BOOL success, NSError *error) {
// if (success) {
// NSLog(@"✅ Survey submitted!");
// [self dismissViewControllerAnimated:YES completion:nil];
// } else {
// NSLog(@"❌ Failed to submit survey: %@", error);
// }
// }];
}
- (NSString *)buildRatesHelperText:(NSArray *)labels {
if (![labels isKindOfClass:[NSArray class]] || labels.count == 0) {
return nil;
}
NSMutableArray *parts = [NSMutableArray array];
for (NSDictionary *item in labels) {
NSNumber *value = item[@"value"];
NSString *label = item[@"label"];
if (value && label && ![label isKindOfClass:[NSNull class]]) {
[parts addObject:[NSString stringWithFormat:@"%@ = %@", value, label]];
}
}
return parts.count > 0 ? [parts componentsJoinedByString:@" "] : nil;
}
@end
...@@ -106,6 +106,8 @@ NS_ASSUME_NONNULL_BEGIN ...@@ -106,6 +106,8 @@ NS_ASSUME_NONNULL_BEGIN
NSDictionary * _Nullable response, NSDictionary * _Nullable response,
NSError * _Nullable error))completion; NSError * _Nullable error))completion;
+ (void)requestSurvey:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END
...@@ -1585,9 +1585,10 @@ ...@@ -1585,9 +1585,10 @@
+ (void)requestDefectMatrix:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion { + (void)requestDefectMatrix:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion {
// if ([APIConfig handleOfflineForAPI:@"DefectMatrix" completion:completion]) { // if ([APIConfig handleOfflineForAPI:@"DefectMatrix" completion:completion]) {
// return; // return;
// } // }
// ✅ URL // ✅ URL
NSURL *url = [APIConfig urlWithPath:@"/framework/issue/getGeneralSettingByUnit"]; NSURL *url = [APIConfig urlWithPath:@"/framework/issue/getGeneralSettingByUnit"];
...@@ -2553,6 +2554,76 @@ ...@@ -2553,6 +2554,76 @@
[task resume]; [task resume];
} }
+ (void)requestSurvey:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion {
if ([APIConfig handleOfflineForAPI:@"Survey" completion:completion]) {
return;
}
NSURL *url = [APIConfig urlWithPath:@"/framework/owner/survey/getSurvey"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
NSDictionary *jsonBody = @{
@"data": @{
@"os": [APIConfig os],
@"drawing_plan_id": [APIConfig drawingPlanId] ?: @"",
}
};
NSLog(@"🌍 request survey: %@", url.absoluteString);
NSLog(@"📦 request survey json: %@", jsonBody);
NSError *jsonError;
NSData *bodyData = [NSJSONSerialization dataWithJSONObject:jsonBody options:0 error:&jsonError];
if (jsonError) {
NSLog(@"❌ JSON Serialization Error: %@", jsonError);
if (completion) completion(NO, nil, jsonError);
return;
}
request.HTTPBody = bodyData;
NSURLSessionDataTask *task = [[NSURLSession sharedSession]
dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"❌ Network Error: %@", error);
dispatch_async(dispatch_get_main_queue(), ^{
completion(NO, nil, error);
});
return;
}
NSError *parseError;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
if (parseError) {
NSLog(@"⚠️ JSON Parse Error: %@", parseError);
dispatch_async(dispatch_get_main_queue(), ^{
completion(NO, nil, parseError);
});
return;
}
NSString *cacheKey = [NSString stringWithFormat:@"Survey_%@", [APIConfig projectId]];
NSDictionary *safeJson = [APIConfig dictionaryByReplacingNullsWithBlanks:json];
[LocalStorage saveDictionary:safeJson forKey:cacheKey];
NSLog(@"💾 Saved to cache: %@", cacheKey);
dispatch_async(dispatch_get_main_queue(), ^{
completion(YES, json, nil);
});
}];
[task resume];
}
#pragma mark - Helper Methods #pragma mark - Helper Methods
+ (NSString *)multipartFormField:(NSString *)name value:(NSString *)value boundary:(NSString *)boundary { + (NSString *)multipartFormField:(NSString *)name value:(NSString *)value boundary:(NSString *)boundary {
return [NSString stringWithFormat:@"--%@\r\nContent-Disposition: form-data; name=\"data[%@]\"\r\n\r\n%@\r\n", boundary, name, value]; return [NSString stringWithFormat:@"--%@\r\nContent-Disposition: form-data; name=\"data[%@]\"\r\n\r\n%@\r\n", boundary, name, value];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment