Commit 82cef0dc authored by Wei Han's avatar Wei Han

code update

parent 4a7abd98
...@@ -239,6 +239,7 @@ ...@@ -239,6 +239,7 @@
TargetAttributes = { TargetAttributes = {
2F9647642E86307D002CC7CB = { 2F9647642E86307D002CC7CB = {
CreatedOnToolsVersion = 26.0.1; CreatedOnToolsVersion = 26.0.1;
LastSwiftMigration = 2620;
}; };
2FC779A82F0E1C310002A1D4 = { 2FC779A82F0E1C310002A1D4 = {
CreatedOnToolsVersion = 26.2; CreatedOnToolsVersion = 26.2;
...@@ -312,6 +313,7 @@ ...@@ -312,6 +313,7 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
BUILD_LIBRARY_FOR_DISTRIBUTION = YES; BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
...@@ -343,6 +345,7 @@ ...@@ -343,6 +345,7 @@
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 4.0; SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
}; };
...@@ -352,6 +355,7 @@ ...@@ -352,6 +355,7 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
BUILD_LIBRARY_FOR_DISTRIBUTION = YES; BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES; DEFINES_MODULE = YES;
......
...@@ -514,7 +514,7 @@ ...@@ -514,7 +514,7 @@
[APIClient requestCancelAppointment:self.appointmentData[@"appointment_id"] [APIClient requestCancelAppointment:self.appointmentData[@"appointment_id"]
reason:remarks reason:remarks
completion:^(NSDictionary *data, NSError *error) completion:^(BOOL success, NSDictionary *data, NSError *error)
{ {
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
......
...@@ -933,7 +933,7 @@ ...@@ -933,7 +933,7 @@
[APIClient requestCancelAppointment:self.appointmentData[@"id"] [APIClient requestCancelAppointment:self.appointmentData[@"id"]
reason:remarks reason:remarks
completion:^(NSDictionary *data, NSError *error) completion:^(BOOL success, NSDictionary *data, NSError *error)
{ {
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
...@@ -966,7 +966,7 @@ ...@@ -966,7 +966,7 @@
} }
-(void) requestGeneralInfo { -(void) requestGeneralInfo {
[APIClient requestGeneralInfo:^(NSDictionary *data, NSError *error) { [APIClient requestGeneralInfo:^(BOOL success, NSDictionary *data, NSError *error) {
if (error) return; if (error) return;
NSDictionary *generalInfo = data[@"Data"]; NSDictionary *generalInfo = data[@"Data"];
self.floorPlanImage = generalInfo[@"image"]; self.floorPlanImage = generalInfo[@"image"];
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
@property (nonatomic, strong) WKWebView *termsWebView; @property (nonatomic, strong) WKWebView *termsWebView;
@property (nonatomic, strong) NSString *termsAndCondition; @property (nonatomic, strong) NSString *termsAndCondition;
@property (nonatomic, strong) NSString *appointmentType; @property (nonatomic, strong) NSString *appointmentType;
@property (nonatomic, assign) BOOL hasLoadedTermsHTML;
// Labels // Labels
@property (nonatomic, strong) UILabel *unitLabel; @property (nonatomic, strong) UILabel *unitLabel;
...@@ -61,12 +62,23 @@ ...@@ -61,12 +62,23 @@
- (void)viewDidLoad { - (void)viewDidLoad {
[super viewDidLoad]; [super viewDidLoad];
self.view.backgroundColor = UIColor.whiteColor; self.view.backgroundColor = UIColor.whiteColor;
[self requestAppointment];
[self requestGeneralInfo];
[self setupHeader]; [self setupHeader];
[self setupFooter]; [self setupFooter];
[self setupUI]; [self setupUI];
} }
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
if (self.termsAndCondition && !self.hasLoadedTermsHTML) {
[self.termsWebView loadHTMLString:self.termsAndCondition baseURL:nil];
self.hasLoadedTermsHTML = YES;
}
}
#pragma mark - Setup UI #pragma mark - Setup UI
- (void)setupUI { - (void)setupUI {
// Scroll view // Scroll view
...@@ -173,41 +185,43 @@ ...@@ -173,41 +185,43 @@
#pragma mark = Overlay t&c #pragma mark = Overlay t&c
- (void)setupTermsOverlay { - (void)setupTermsOverlay {
// Overlay background
self.termsOverlay = [[UIView alloc] init]; self.termsOverlay = [[UIView alloc] init];
self.termsOverlay.backgroundColor = UIColor.whiteColor; self.termsOverlay.backgroundColor = UIColor.whiteColor;
self.termsOverlay.translatesAutoresizingMaskIntoConstraints = NO; self.termsOverlay.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.termsOverlay]; [self.view addSubview:self.termsOverlay];
UILayoutGuide *safe = self.view.safeAreaLayoutGuide;
[NSLayoutConstraint activateConstraints:@[ [NSLayoutConstraint activateConstraints:@[
[self.termsOverlay.topAnchor constraintEqualToAnchor:self.headerBar.bottomAnchor], [self.termsOverlay.topAnchor constraintEqualToAnchor:self.headerBar.bottomAnchor],
[self.termsOverlay.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], [self.termsOverlay.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.termsOverlay.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], [self.termsOverlay.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.termsOverlay.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor], [self.termsOverlay.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor]
]]; ]];
// Title
self.termsTitleLabel = [[UILabel alloc] init]; self.termsTitleLabel = [[UILabel alloc] init];
self.termsTitleLabel.text = @"Terms & Conditions"; self.termsTitleLabel.text = @"Terms & Conditions";
self.termsTitleLabel.font = [UIFont boldSystemFontOfSize:18]; self.termsTitleLabel.font = [UIFont boldSystemFontOfSize:18];
self.termsTitleLabel.translatesAutoresizingMaskIntoConstraints = NO; self.termsTitleLabel.translatesAutoresizingMaskIntoConstraints = NO;
[self.termsOverlay addSubview:self.termsTitleLabel]; [self.termsOverlay addSubview:self.termsTitleLabel];
// WebView container
self.termsContainer = [[UIView alloc] init]; self.termsContainer = [[UIView alloc] init];
self.termsContainer.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1.0]; self.termsContainer.backgroundColor = [UIColor clearColor];
self.termsContainer.layer.cornerRadius = 12.0; self.termsContainer.layer.cornerRadius = 12.0;
self.termsContainer.translatesAutoresizingMaskIntoConstraints = NO; self.termsContainer.translatesAutoresizingMaskIntoConstraints = NO;
[self.termsOverlay addSubview:self.termsContainer]; [self.termsOverlay addSubview:self.termsContainer];
// WKWebView // WKWebView
self.termsWebView = [[WKWebView alloc] initWithFrame:CGRectZero]; self.termsWebView = [[WKWebView alloc] initWithFrame:CGRectZero];
self.termsWebView.translatesAutoresizingMaskIntoConstraints = NO; self.termsWebView.translatesAutoresizingMaskIntoConstraints = NO;
self.termsWebView.scrollView.delegate = self; self.termsWebView.scrollView.delegate = self;
self.termsWebView.navigationDelegate = self; self.termsWebView.navigationDelegate = self;
self.termsWebView.opaque = NO;
self.termsWebView.backgroundColor = [UIColor clearColor];
[self.termsContainer addSubview:self.termsWebView]; [self.termsContainer addSubview:self.termsWebView];
self.termsContainer.backgroundColor = [UIColor yellowColor];
self.termsWebView.backgroundColor = [UIColor redColor];
// Agree button // Agree button
self.agreeButton = [UIButton buttonWithType:UIButtonTypeSystem]; self.agreeButton = [UIButton buttonWithType:UIButtonTypeSystem];
self.agreeButton.translatesAutoresizingMaskIntoConstraints = NO; self.agreeButton.translatesAutoresizingMaskIntoConstraints = NO;
...@@ -219,23 +233,23 @@ ...@@ -219,23 +233,23 @@
[self.agreeButton addTarget:self action:@selector(handleAgreeTapped) [self.agreeButton addTarget:self action:@selector(handleAgreeTapped)
forControlEvents:UIControlEventTouchUpInside]; forControlEvents:UIControlEventTouchUpInside];
[self.termsOverlay addSubview:self.agreeButton]; [self.termsOverlay addSubview:self.agreeButton];
// Layout // Layout constraints
[NSLayoutConstraint activateConstraints:@[ [NSLayoutConstraint activateConstraints:@[
[self.termsTitleLabel.topAnchor constraintEqualToAnchor:self.termsOverlay.topAnchor constant:40], [self.termsTitleLabel.topAnchor constraintEqualToAnchor:self.termsOverlay.topAnchor constant:40],
[self.termsTitleLabel.leadingAnchor constraintEqualToAnchor:self.termsOverlay.leadingAnchor constant:20], [self.termsTitleLabel.leadingAnchor constraintEqualToAnchor:self.termsOverlay.leadingAnchor constant:20],
[self.termsTitleLabel.trailingAnchor constraintEqualToAnchor:self.termsOverlay.trailingAnchor constant:-20], [self.termsTitleLabel.trailingAnchor constraintEqualToAnchor:self.termsOverlay.trailingAnchor constant:-20],
[self.termsContainer.topAnchor constraintEqualToAnchor:self.termsTitleLabel.bottomAnchor constant:12], [self.termsContainer.topAnchor constraintEqualToAnchor:self.termsTitleLabel.bottomAnchor constant:12],
[self.termsContainer.leadingAnchor constraintEqualToAnchor:self.termsOverlay.leadingAnchor constant:20], [self.termsContainer.leadingAnchor constraintEqualToAnchor:self.termsOverlay.leadingAnchor constant:20],
[self.termsContainer.trailingAnchor constraintEqualToAnchor:self.termsOverlay.trailingAnchor constant:-20], [self.termsContainer.trailingAnchor constraintEqualToAnchor:self.termsOverlay.trailingAnchor constant:-20],
[self.termsContainer.bottomAnchor constraintEqualToAnchor:self.agreeButton.topAnchor constant:-20], [self.termsContainer.bottomAnchor constraintEqualToAnchor:self.agreeButton.topAnchor constant:-20],
[self.termsWebView.topAnchor constraintEqualToAnchor:self.termsContainer.topAnchor], [self.termsWebView.topAnchor constraintEqualToAnchor:self.termsContainer.topAnchor],
[self.termsWebView.leadingAnchor constraintEqualToAnchor:self.termsContainer.leadingAnchor], [self.termsWebView.leadingAnchor constraintEqualToAnchor:self.termsContainer.leadingAnchor],
[self.termsWebView.trailingAnchor constraintEqualToAnchor:self.termsContainer.trailingAnchor], [self.termsWebView.trailingAnchor constraintEqualToAnchor:self.termsContainer.trailingAnchor],
[self.termsWebView.bottomAnchor constraintEqualToAnchor:self.termsContainer.bottomAnchor], [self.termsWebView.bottomAnchor constraintEqualToAnchor:self.termsContainer.bottomAnchor],
[self.agreeButton.leadingAnchor constraintEqualToAnchor:self.termsOverlay.leadingAnchor constant:40], [self.agreeButton.leadingAnchor constraintEqualToAnchor:self.termsOverlay.leadingAnchor constant:40],
[self.agreeButton.trailingAnchor constraintEqualToAnchor:self.termsOverlay.trailingAnchor constant:-40], [self.agreeButton.trailingAnchor constraintEqualToAnchor:self.termsOverlay.trailingAnchor constant:-40],
[self.agreeButton.bottomAnchor constraintEqualToAnchor:self.termsOverlay.safeAreaLayoutGuide.bottomAnchor constant:-20], [self.agreeButton.bottomAnchor constraintEqualToAnchor:self.termsOverlay.safeAreaLayoutGuide.bottomAnchor constant:-20],
...@@ -243,7 +257,6 @@ ...@@ -243,7 +257,6 @@
]]; ]];
} }
#pragma mark - Labels #pragma mark - Labels
- (void)setupLabels:(UIView *)parent { - (void)setupLabels:(UIView *)parent {
self.unitLabel = [[UILabel alloc] init]; self.unitLabel = [[UILabel alloc] init];
...@@ -450,7 +463,7 @@ ...@@ -450,7 +463,7 @@
#pragma mark - api #pragma mark - api
- (void)requestAppointment { - (void)requestAppointment {
[APIClient requestAppointment:^(NSDictionary *data, NSError *error) { [APIClient requestAppointment:^(BOOL success, NSDictionary *data, NSError *error) {
if (error) return; if (error) return;
if (!data[@"Data"]) return; if (!data[@"Data"]) return;
...@@ -477,34 +490,35 @@ ...@@ -477,34 +490,35 @@
NSArray *slots = selectedTypeDict[@"slots"] ?: @[]; NSArray *slots = selectedTypeDict[@"slots"] ?: @[];
self.allSlots = slots; // store all raw slots self.allSlots = slots; // store all raw slots
// --- 3️⃣ Load Terms HTML --- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSString *termsHTML = selectedTypeDict[@"terms"] ?: @""; if (!self.termsAndCondition) {
NSString *styledHTML = [NSString stringWithFormat: NSString *termsHTML = selectedTypeDict[@"terms"] ?: @"";
@"<html>" NSLog(@"termsHTML: %@", termsHTML);
"<head>" NSString *styledHTML = [NSString stringWithFormat:
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0\">" @"<html>"
"<style>" "<head>"
"body { font-size: 14px; font-family: -apple-system; line-height: 1.5; padding: 12px; background-color: #F9F9F9; color: #000000; }" "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0\">"
"p, div, span, li { color: #000000 !important; }" "<style>"
"p { margin-bottom: 12px; }" "body { font-size: 16px; font-family: -apple-system; line-height: 1.5; padding: 12px; background-color: #F9F9F9; color: #000000; }"
"</style>" "p, div, span, li { color: #000000 !important; }"
"</head>" "p { margin-bottom: 12px; }"
"<body>%@</body>" "</style>"
"</html>", termsHTML]; "</head>"
"<body>%@</body>"
"</html>", termsHTML];
self.termsAndCondition = styledHTML;
dispatch_async(dispatch_get_main_queue(), ^{
[self.termsWebView loadHTMLString:styledHTML baseURL:nil]; self.termsAndCondition = styledHTML;
[self buildMarkedDatesFromSlots:slots]; }
[self.calendarView.collectionView reloadData]; [self.termsContainer layoutIfNeeded];
}); [self.termsWebView layoutIfNeeded];
[self.termsWebView loadHTMLString:self.termsAndCondition baseURL:nil];
});
}]; }];
} }
-(void) requestGeneralInfo { -(void) requestGeneralInfo {
[APIClient requestGeneralInfo:^(NSDictionary *data, NSError *error) { [APIClient requestGeneralInfo:^(BOOL success, NSDictionary *data, NSError *error) {
if (error) return; if (error) return;
NSDictionary *generalInfo = data[@"Data"]; NSDictionary *generalInfo = data[@"Data"];
...@@ -705,7 +719,7 @@ ...@@ -705,7 +719,7 @@
dispatch_group_t group = dispatch_group_create(); dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group); dispatch_group_enter(group);
[APIClient requestAppointment:^(NSDictionary *data, NSError *error) { [APIClient requestAppointment:^(BOOL success, NSDictionary *data, NSError *error) {
if (data[@"Data"]) { if (data[@"Data"]) {
NSDictionary *dataDict = data[@"Data"]; NSDictionary *dataDict = data[@"Data"];
self.appointmentData = dataDict; self.appointmentData = dataDict;
...@@ -730,7 +744,7 @@ ...@@ -730,7 +744,7 @@
}]; }];
dispatch_group_enter(group); dispatch_group_enter(group);
[APIClient requestGeneralInfo:^(NSDictionary *data, NSError *error) { [APIClient requestGeneralInfo:^(BOOL success, NSDictionary *data, NSError *error) {
id reps = data[@"Data"][@"representative"]; id reps = data[@"Data"][@"representative"];
self.representativeList = [reps isKindOfClass:[NSArray class]] ? reps : @[]; self.representativeList = [reps isKindOfClass:[NSArray class]] ? reps : @[];
dispatch_group_leave(group); dispatch_group_leave(group);
......
...@@ -927,7 +927,7 @@ ...@@ -927,7 +927,7 @@
- (void)requestDashboardInfo { - (void)requestDashboardInfo {
[self.loadingView startAnimating]; [self.loadingView startAnimating];
[APIClient requestDashboardInfo:^(NSDictionary *data, NSError *error) { [APIClient requestDashboardInfo:^(BOOL success, NSDictionary *data, NSError *error) {
[self.loadingView stopAnimating]; [self.loadingView stopAnimating];
......
...@@ -19,6 +19,7 @@ NS_ASSUME_NONNULL_BEGIN ...@@ -19,6 +19,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, copy) NSString *projectName; @property (nonatomic, copy) NSString *projectName;
@property (nonatomic, copy) NSString *projectId; @property (nonatomic, copy) NSString *projectId;
@property (nonatomic, copy) NSString *drawingPlanId; @property (nonatomic, copy) NSString *drawingPlanId;
@property (nonatomic, copy) NSString *projectLogo;
@end @end
......
...@@ -541,7 +541,7 @@ typedef struct { ...@@ -541,7 +541,7 @@ typedef struct {
#pragma mark - api #pragma mark - api
- (void)requestGeneralInfo { - (void)requestGeneralInfo {
[APIClient requestGeneralInfo:^(NSDictionary *data, NSError *error) { [APIClient requestGeneralInfo:^(BOOL success, NSDictionary *data, NSError *error) {
if (error || !data) { if (error || !data) {
NSLog(@"❌ General info error: %@", error.localizedDescription); NSLog(@"❌ General info error: %@", error.localizedDescription);
return; return;
......
...@@ -155,34 +155,49 @@ ...@@ -155,34 +155,49 @@
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView - (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath { cellForItemAtIndexPath:(NSIndexPath *)indexPath {
ProjectCardCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"ProjectCardCell" ProjectCardCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"ProjectCardCell"
forIndexPath:indexPath]; forIndexPath:indexPath];
// Default placeholder
cell.imageView.image = [UIImage systemImageNamed:@"photo"]; cell.imageView.image = [UIImage systemImageNamed:@"photo"];
NSDictionary *project = self.projects[indexPath.item]; NSDictionary *project = self.projects[indexPath.item];
// Project name // Project name
cell.nameLabel.text = project[@"project_name"]; id projectName = project[@"project_name"];
cell.nameLabel.text = [projectName isKindOfClass:[NSString class]] ? projectName : @"";
// Project logo
NSString *logoURLString = project[@"logo"] ?: project[@"logo_thumbnail"]; // Get logo URL safely
NSURL *url = [NSURL URLWithString:logoURLString]; NSString *logo = project[@"logo"];
NSString *thumb = project[@"logo_thumbnail"];
// Async load image (simple placeholder approach)
NSIndexPath *currentIndexPath = indexPath; NSString *logoURLString = (logo.length > 0) ? logo :
(thumb.length > 0) ? thumb : nil;
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = data ? [UIImage imageWithData:data] : nil; NSURL *url = [NSURL URLWithString:logoURLString ?: @""];
dispatch_async(dispatch_get_main_queue(), ^{ // Async load image safely
NSIndexPath *visibleIndexPath = [collectionView indexPathForCell:cell]; if (url) {
if (visibleIndexPath && visibleIndexPath.item == currentIndexPath.item) { NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url
cell.imageView.image = image ?: [UIImage systemImageNamed:@"photo"]; completionHandler:^(NSData * _Nullable data,
} NSURLResponse * _Nullable response,
}); NSError * _Nullable error) {
}); UIImage *image = data ? [UIImage imageWithData:data] : nil;
if (!image) return; // leave placeholder
dispatch_async(dispatch_get_main_queue(), ^{
// Only update if the cell is still visible at this indexPath
ProjectCardCell *updateCell = (ProjectCardCell *)[collectionView cellForItemAtIndexPath:indexPath];
if (updateCell) {
updateCell.imageView.image = image;
}
});
}];
[task resume];
}
return cell; return cell;
} }
...@@ -194,6 +209,7 @@ ...@@ -194,6 +209,7 @@
vc.projectName = project[@"project_name"]; vc.projectName = project[@"project_name"];
vc.units = project[@"unit"]; vc.units = project[@"unit"];
vc.drawerController = self.drawerController; vc.drawerController = self.drawerController;
vc.projectLogo = project[@"logo"] ?: project[@"logo_thumbnail"];
vc.modalPresentationStyle = UIModalPresentationFullScreen; vc.modalPresentationStyle = UIModalPresentationFullScreen;
[self.navigationController pushViewController:vc animated:YES]; [self.navigationController pushViewController:vc animated:YES];
...@@ -212,7 +228,7 @@ ...@@ -212,7 +228,7 @@
#pragma mark - API #pragma mark - API
- (void)requestProjectList { - (void)requestProjectList {
[APIClient requestProjectList:^(NSDictionary *data, NSError *error) { [APIClient requestProjectList:^(BOOL success, NSDictionary *data, NSError *error) {
// debug // debug
NSString *plainText = [NSString stringWithFormat:@"%@", data]; NSString *plainText = [NSString stringWithFormat:@"%@", data];
...@@ -259,7 +275,7 @@ ...@@ -259,7 +275,7 @@
} }
- (void)requestCompanyCode { - (void)requestCompanyCode {
[APIClient requestCompanyCode:@"kita" completion:^(NSDictionary *data, NSError *error) { [APIClient requestCompanyCode:@"kita" completion:^(BOOL success, NSDictionary *data, NSError *error) {
// debug // debug
NSString *plainText = [NSString stringWithFormat:@"%@", data]; NSString *plainText = [NSString stringWithFormat:@"%@", data];
......
...@@ -13,5 +13,6 @@ ...@@ -13,5 +13,6 @@
@property (nonatomic, copy) NSString *projectId; @property (nonatomic, copy) NSString *projectId;
@property (nonatomic, copy) NSString *projectName; @property (nonatomic, copy) NSString *projectName;
@property (nonatomic, copy) NSArray *units; @property (nonatomic, copy) NSArray *units;
@property (nonatomic, copy) NSString *projectLogo;
@end @end
...@@ -260,13 +260,14 @@ didSelectRowAtIndexPath:(NSIndexPath *)indexPath { ...@@ -260,13 +260,14 @@ didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *projectId = [unit[@"project_id"] description]; NSString *projectId = [unit[@"project_id"] description];
NSString *drawingPlanId = [unit[@"id"] description]; NSString *drawingPlanId = [unit[@"id"] description];
NSLog(@"self.projectLogo: %@", self.projectLogo);
DashboardViewController *vc = [[DashboardViewController alloc] init]; DashboardViewController *vc = [[DashboardViewController alloc] init];
vc.projectCode = unit[@"name"] ?: @""; vc.projectCode = unit[@"name"] ?: @"";
vc.projectName = self.projectName; vc.projectName = self.projectName;
vc.projectId = projectId ?: @""; vc.projectId = projectId ?: @"";
vc.drawingPlanId = drawingPlanId ?: @""; vc.drawingPlanId = drawingPlanId ?: @"";
vc.drawerController = self.drawerController; vc.drawerController = self.drawerController;
vc.projectLogo = self.projectLogo;
vc.modalPresentationStyle = UIModalPresentationFullScreen; vc.modalPresentationStyle = UIModalPresentationFullScreen;
[self.navigationController pushViewController:vc animated:YES]; [self.navigationController pushViewController:vc animated:YES];
} }
......
...@@ -597,7 +597,7 @@ didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> * ...@@ -597,7 +597,7 @@ didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *
// ✅ JSON ONLY // ✅ JSON ONLY
[APIClient submitAddInfo:self.issueID [APIClient submitAddInfo:self.issueID
remarks:self.commentTextView.text remarks:self.commentTextView.text
completion:^(NSDictionary *response, NSError *error) { completion:^(BOOL success, NSDictionary *response, NSError *error) {
[self handleSubmitResponse:response error:error]; [self handleSubmitResponse:response error:error];
}]; }];
return; return;
...@@ -607,7 +607,7 @@ didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> * ...@@ -607,7 +607,7 @@ didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *
images:images images:images
mediaURL:self.selectedMediaURL mediaURL:self.selectedMediaURL
mediaType:mediaType mediaType:mediaType
completion:^(NSDictionary *response, NSError *error) { completion:^(BOOL success, NSDictionary *response, NSError *error) {
[self handleSubmitResponse:response error:error]; [self handleSubmitResponse:response error:error];
}]; }];
} }
......
...@@ -957,7 +957,7 @@ didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> * ...@@ -957,7 +957,7 @@ didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *
[APIClient submitUpdateIssue:updateData [APIClient submitUpdateIssue:updateData
images:self.addedImages images:self.addedImages
completion:^(NSDictionary * _Nullable response, NSError * _Nullable error) { completion:^(BOOL success, NSDictionary *response, NSError *error){
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
if (error) { if (error) {
[self showAlertWithTitle:@"Update Failed" message:error.localizedDescription]; [self showAlertWithTitle:@"Update Failed" message:error.localizedDescription];
...@@ -1043,7 +1043,7 @@ didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> * ...@@ -1043,7 +1043,7 @@ didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *
[APIClient submitAddIssue:issueData [APIClient submitAddIssue:issueData
images:self.uploadedImages images:self.uploadedImages
completion:^(NSDictionary *response, NSError *error) { completion:^(BOOL success, NSDictionary *response, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
if (error) { if (error) {
NSLog(@"❌ Submission failed: %@", error.localizedDescription); NSLog(@"❌ Submission failed: %@", error.localizedDescription);
......
...@@ -69,7 +69,7 @@ ...@@ -69,7 +69,7 @@
- (void)handleGetUnitPlan { - (void)handleGetUnitPlan {
NSLog(@"🌐 requesting Unit Plan data..."); NSLog(@"🌐 requesting Unit Plan data...");
[APIClient requestGetUnitPlan:^(NSDictionary *data, NSError *error) { [APIClient requestGetUnitPlan:^(BOOL success, NSDictionary *data, NSError *error) {
if (error) { if (error) {
NSLog(@"❌ Unit Plan request failed: %@", error.localizedDescription); NSLog(@"❌ Unit Plan request failed: %@", error.localizedDescription);
return; return;
...@@ -710,7 +710,7 @@ ...@@ -710,7 +710,7 @@
- (void)handleSettingsByLocation:(NSString *)locationID planID:(NSString *)planID { - (void)handleSettingsByLocation:(NSString *)locationID planID:(NSString *)planID {
[APIClient requestSettingsByLocation:locationID [APIClient requestSettingsByLocation:locationID
completion:^(NSDictionary *data, NSError *error) { completion:^(BOOL success, NSDictionary *data, NSError *error) {
if (error) { if (error) {
NSLog(@"❌ Error requesting settings: %@", error); NSLog(@"❌ Error requesting settings: %@", error);
return; return;
......
...@@ -127,7 +127,7 @@ ...@@ -127,7 +127,7 @@
#pragma mark - API request/response #pragma mark - API request/response
- (void)handleIssues { - (void)handleIssues {
[APIClient requestHistory:self.issueID [APIClient requestHistory:self.issueID
completion:^(NSDictionary *data, NSError *error) { completion:^(BOOL success, NSDictionary *data, NSError *error) {
if (error) { if (error) {
NSLog(@"❌ Error requesting history: %@", error); NSLog(@"❌ Error requesting history: %@", error);
return; return;
......
...@@ -300,7 +300,7 @@ ...@@ -300,7 +300,7 @@
- (void)handleGetIssue { - (void)handleGetIssue {
NSLog(@"🌐 requesting Issue data..."); NSLog(@"🌐 requesting Issue data...");
[APIClient requestIssues:^(NSDictionary *data, NSError *error) { [APIClient requestIssues:^(BOOL success, NSDictionary *data, NSError *error) {
if (error) { if (error) {
NSLog(@"❌ Issue request failed: %@", error.localizedDescription); NSLog(@"❌ Issue request failed: %@", error.localizedDescription);
return; return;
......
...@@ -286,7 +286,7 @@ ...@@ -286,7 +286,7 @@
[searchContainer.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor constant:50], [searchContainer.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor constant:50],
[searchContainer.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:8], [searchContainer.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:8],
[searchContainer.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-8], [searchContainer.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-8],
[searchContainer.heightAnchor constraintEqualToConstant:100], [searchContainer.heightAnchor constraintEqualToConstant:120],
[self.searchBar.leadingAnchor constraintEqualToAnchor:searchContainer.leadingAnchor], [self.searchBar.leadingAnchor constraintEqualToAnchor:searchContainer.leadingAnchor],
[self.searchBar.trailingAnchor constraintEqualToAnchor:searchContainer.trailingAnchor], [self.searchBar.trailingAnchor constraintEqualToAnchor:searchContainer.trailingAnchor],
...@@ -383,7 +383,7 @@ ...@@ -383,7 +383,7 @@
#pragma mark - Data #pragma mark - Data
- (void)requestIssues { - (void)requestIssues {
[APIClient requestIssues:^(NSDictionary *data, NSError *error) { [APIClient requestIssues:^(BOOL success, NSDictionary *data, NSError *error) {
if (error) return; if (error) return;
NSArray *allIssues = data[@"Data"] ?: @[]; NSArray *allIssues = data[@"Data"] ?: @[];
......
...@@ -264,7 +264,7 @@ ...@@ -264,7 +264,7 @@
- (void)requestDeleteIssue:(NSString *)issueID remarks:(NSString *)remarks { - (void)requestDeleteIssue:(NSString *)issueID remarks:(NSString *)remarks {
NSLog(@"🚀 Sending DELETE ISSUE for ID=%@, remarks=%@", issueID, remarks); NSLog(@"🚀 Sending DELETE ISSUE for ID=%@, remarks=%@", issueID, remarks);
[APIClient requestDeleteIssue:issueID remarks:remarks completion:^(NSDictionary *data, NSError *error) { [APIClient requestDeleteIssue:issueID remarks:remarks completion:^(BOOL success, NSDictionary *data, NSError *error) {
if (error) { if (error) {
NSLog(@"Error %@", error.localizedDescription); NSLog(@"Error %@", error.localizedDescription);
return; return;
...@@ -303,7 +303,7 @@ ...@@ -303,7 +303,7 @@
[APIClient requestVoidIssue:ids [APIClient requestVoidIssue:ids
remarks:remarks remarks:remarks
completion:^(NSDictionary *data, NSError *error) { completion:^(BOOL success, NSDictionary *data, NSError *error) {
if (error) { if (error) {
NSLog(@"Error %@", error.localizedDescription); NSLog(@"Error %@", error.localizedDescription);
return; return;
......
...@@ -105,6 +105,7 @@ UICollectionViewDataSource ...@@ -105,6 +105,7 @@ UICollectionViewDataSource
@implementation SyncProjectViewController @implementation SyncProjectViewController
- (void)viewDidLoad { - (void)viewDidLoad {
[super viewDidLoad]; [super viewDidLoad];
self.view.backgroundColor = [UIColor colorWithWhite:0.96 alpha:1.0];
self.projects = [NSMutableArray array]; self.projects = [NSMutableArray array];
self.selectedUnits = [NSMutableArray array]; self.selectedUnits = [NSMutableArray array];
...@@ -480,7 +481,7 @@ didSelectItemAtIndexPath:(NSIndexPath *)indexPath { ...@@ -480,7 +481,7 @@ didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
[self showLoading:YES]; [self showLoading:YES];
[APIClient requestProjectList:^(NSDictionary *data, NSError *error) { [APIClient requestProjectList:^(BOOL success, NSDictionary *data, NSError *error) {
// debug // debug
NSString *plainText = [NSString stringWithFormat:@"%@", data]; NSString *plainText = [NSString stringWithFormat:@"%@", data];
......
...@@ -8,22 +8,22 @@ NS_ASSUME_NONNULL_BEGIN ...@@ -8,22 +8,22 @@ NS_ASSUME_NONNULL_BEGIN
+ (void)requestAccessItem:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion; + (void)requestAccessItem:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion;
+ (void)requestGetUnitPlan:(void (^)(NSDictionary * _Nullable data, NSError * _Nullable error))completion; + (void)requestGetUnitPlan:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * error))completion;
+ (void)requestSettingsByLocation:(NSString * _Nonnull)locationID + (void)requestSettingsByLocation:(NSString * _Nonnull)locationID
completion:(void (^)(NSDictionary * _Nullable data, NSError * _Nullable error))completion; completion:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * error))completion;
+ (void)submitAddIssue:(NSDictionary * _Nonnull)params + (void)submitAddIssue:(NSDictionary * _Nonnull)params
images:(NSArray<UIImage *> * _Nullable)images images:(NSArray<UIImage *> * _Nullable)images
completion:(void (^)(NSDictionary * _Nullable data, NSError * _Nullable error))completion; completion:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * error))completion;
+ (void)submitUpdateIssue:(NSDictionary * _Nonnull)updateData + (void)submitUpdateIssue:(NSDictionary * _Nonnull)updateData
images:(NSArray<UIImage *> * _Nullable)images images:(NSArray<UIImage *> * _Nullable)images
completion:(void (^)(NSDictionary * _Nullable response, NSError * _Nullable error))completion; completion:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion;
+ (void)requestAppointment:(void (^)(NSDictionary * _Nullable data, NSError * _Nullable error))completion; + (void)requestAppointment:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * error))completion;
+ (void)requestGeneralInfo:(void (^)(NSDictionary * _Nullable data, NSError * _Nullable error))completion; + (void)requestGeneralInfo:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * error))completion;
+ (void)submitAppointment:(NSDictionary *)appointmentData + (void)submitAppointment:(NSDictionary *)appointmentData
completion:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion; completion:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion;
...@@ -33,52 +33,52 @@ NS_ASSUME_NONNULL_BEGIN ...@@ -33,52 +33,52 @@ NS_ASSUME_NONNULL_BEGIN
+ (void)requestCancelAppointment:(id)appointmentId + (void)requestCancelAppointment:(id)appointmentId
reason:(NSString *)reason reason:(NSString *)reason
completion:(void (^)(NSDictionary * _Nullable data, NSError * _Nullable error))completion; completion:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * error))completion;
+ (void)requestDashboardInfo:(void (^)(NSDictionary *data, NSError *error))completion; + (void)requestDashboardInfo:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * error))completion;
+ (void)requestAnnouncement:(void (^)(NSDictionary *data, NSError *error))completion; + (void)requestAnnouncement:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * error))completion;
+ (void)requestHistory:(NSString *)issueID + (void)requestHistory:(NSString *)issueID
completion:(void (^)(NSDictionary *data, NSError *error))completion; completion:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * error))completion;
+(void)submitAddInfo:(NSString *)issueID +(void)submitAddInfo:(NSString *)issueID
remarks:(NSString *)remarks remarks:(NSString *)remarks
completion:(void (^)(NSDictionary *data, NSError *error))completion; completion:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * error))completion;
+ (void)uploadAddInfo:(NSString *)issueID + (void)uploadAddInfo:(NSString *)issueID
remarks:(NSString *)remarks remarks:(NSString *)remarks
images:(NSArray<UIImage *> *)images images:(NSArray<UIImage *> *)images
mediaURL:(NSURL *)mediaURL mediaURL:(NSURL *)mediaURL
mediaType:(NSString *)mediaType mediaType:(NSString *)mediaType
completion:(void (^)(NSDictionary *data, NSError *error))completion; completion:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * error))completion;
+ (void)requestIssues:(void (^)(NSDictionary *data, NSError *error))completion; + (void)requestIssues:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * error))completion;
+ (void)requestVoidIssue:(id)issueID + (void)requestVoidIssue:(id)issueID
remarks:(NSString *)remarks remarks:(NSString *)remarks
completion:(void (^)(NSDictionary *data, NSError *error))completion; completion:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * error))completion;
+ (void)requestDeleteIssue:(id)issueID + (void)requestDeleteIssue:(id)issueID
remarks:(NSString *)remarks remarks:(NSString *)remarks
completion:(void (^)(NSDictionary *data, NSError *error))completion; completion:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * error))completion;
+ (void)requestCommonArea:(void (^)(NSDictionary * _Nullable data, NSError * _Nullable error))completion; + (void)requestCommonArea:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * error))completion;
+ (void)requestGeneralSettings:(void (^)(NSDictionary * _Nullable data, NSError * _Nullable error))completion; + (void)requestGeneralSettings:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * error))completion;
+ (void)requestDefectMatrix:(void (^)(NSDictionary * _Nullable data, NSError * _Nullable error))completion; + (void)requestDefectMatrix:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * error))completion;
+ (void)requestProjectList:(void (^)(NSDictionary * _Nullable data, NSError * _Nullable error))completion; + (void)requestProjectList:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * error))completion;
+ (void)requestArrayImage:(NSArray *)imageArray + (void)requestArrayImage:(NSArray *)imageArray
completion:(void (^)(NSDictionary *data, NSError *error))completion; completion:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * error))completion;
+ (void)downloadAndCacheImage:(NSURL *)url + (void)downloadAndCacheImage:(NSURL *)url
completion:(void (^)(BOOL success))completion; completion:(void (^)(BOOL success, NSString *filePath))completion;
+ (void)requestCompanyCode:(NSString *)companyCode + (void)requestCompanyCode:(NSString *)companyCode
completion:(void (^)(NSDictionary * _Nullable data, NSError * _Nullable error))completion; completion:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * error))completion;
@end @end
......
...@@ -33,6 +33,13 @@ NS_ASSUME_NONNULL_BEGIN ...@@ -33,6 +33,13 @@ NS_ASSUME_NONNULL_BEGIN
/// JSON string form (what your APIs expect) /// JSON string form (what your APIs expect)
+ (NSString *)deviceInfoJSONString; + (NSString *)deviceInfoJSONString;
//Offline
+ (BOOL)handleOfflineForAPI:(NSString *)apiName
completion:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion;
//Null
+ (NSDictionary *)dictionaryByReplacingNullsWithBlanks:(NSDictionary *)dict;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END
......
// APIConfig.mm // APIConfig.mm
#import "APIConfig.h" #import "APIConfig.h"
#import "LocalStorage.h"
#import "NetworkManager.h"
static NSString *kBaseURL = @"https://kitadev.commudesk.com/api"; static NSString *kBaseURL = @"https://kitadev.commudesk.com/api";
static NSString *kDrawingPlanId = @""; static NSString *kDrawingPlanId = @"";
...@@ -89,4 +91,67 @@ static NSString *kAuthToken = @"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI ...@@ -89,4 +91,67 @@ static NSString *kAuthToken = @"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
} }
#pragma mark - Offline Handling
+ (BOOL)handleOfflineForAPI:(NSString *)apiName
completion:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion {
NSString *cacheKey =
[NSString stringWithFormat:@"%@_%@", apiName, [self projectId]];
if (![NetworkManager.sharedManager isConnected]) {
NSDictionary *cached = [LocalStorage loadDictionaryForKey:cacheKey];
if (cached) {
NSLog(@"🟡 Loaded from cache: %@", cacheKey);
if (completion) completion(YES, cached, nil);
} else {
NSError *offlineErr =
[NSError errorWithDomain:@"OfflineError"
code:-1
userInfo:@{
NSLocalizedDescriptionKey:
@"No network and no cached data"
}];
if (completion) completion(NO, nil, offlineErr);
}
return YES; // offline handled
}
return NO; // proceed with online request
}
#pragma mark - Null Handling
+ (NSDictionary *)dictionaryByReplacingNullsWithBlanks:(NSDictionary *)dict {
NSMutableDictionary *result = [NSMutableDictionary dictionary];
for (NSString *key in dict) {
id value = dict[key];
if (value == [NSNull null]) {
result[key] = @""; // or NSNull-safe replacement
} else if ([value isKindOfClass:[NSDictionary class]]) {
result[key] = [self dictionaryByReplacingNullsWithBlanks:value];
} else if ([value isKindOfClass:[NSArray class]]) {
result[key] = [self arrayByReplacingNullsWithBlanks:value];
} else {
result[key] = value;
}
}
return result;
}
+ (NSArray *)arrayByReplacingNullsWithBlanks:(NSArray *)array {
NSMutableArray *result = [NSMutableArray array];
for (id obj in array) {
if (obj == [NSNull null]) {
[result addObject:@""]; // or other safe value
} else if ([obj isKindOfClass:[NSDictionary class]]) {
[result addObject:[self dictionaryByReplacingNullsWithBlanks:obj]];
} else if ([obj isKindOfClass:[NSArray class]]) {
[result addObject:[self arrayByReplacingNullsWithBlanks:obj]];
} else {
[result addObject:obj];
}
}
return result;
}
@end @end
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