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

code update

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