Commit 1323f31a authored by Wei Han's avatar Wei Han

fixed drawer logic

parent 7735252a
...@@ -330,7 +330,7 @@ ...@@ -330,7 +330,7 @@
#pragma mark - helpers #pragma mark - helpers
- (void)onBack { - (void)onBack {
[self dismissViewControllerAnimated:YES completion:nil]; [self.navigationController popViewControllerAnimated:YES];
} }
@end @end
......
...@@ -4,8 +4,6 @@ ...@@ -4,8 +4,6 @@
@interface AppointmentDetailsViewController : UIViewController @interface AppointmentDetailsViewController : UIViewController
@property (nonatomic, strong) NSString *appointmentID;
@property (nonatomic, strong) NSDictionary *appointmentData; @property (nonatomic, strong) NSDictionary *appointmentData;
@end @end
...@@ -72,6 +72,8 @@ ...@@ -72,6 +72,8 @@
NSLog(@"dashboard.drawerController = %@", self.drawerController); NSLog(@"dashboard.drawerController = %@", self.drawerController);
//[[OfflineSyncManager shared] clearOfflineQueue]; //[[OfflineSyncManager shared] clearOfflineQueue];
[[NSNotificationCenter defaultCenter] postNotificationName:@"ShowHiddenButtonNotification" object:@(YES)];
} }
- (void)viewWillAppear:(BOOL)animated { - (void)viewWillAppear:(BOOL)animated {
...@@ -102,7 +104,7 @@ ...@@ -102,7 +104,7 @@
}]; }];
dispatch_group_enter(group); dispatch_group_enter(group);
[APIClient requestAnnouncement:^(BOOL success, NSDictionary *data, NSError *error) { [APIClient requestClientAnnouncement:^(BOOL success, NSDictionary *data, NSError *error) {
if (!error) announcementData = data; if (!error) announcementData = data;
dispatch_group_leave(group); dispatch_group_leave(group);
}]; }];
...@@ -1431,7 +1433,6 @@ ...@@ -1431,7 +1433,6 @@
[self presentViewController:vc animated:YES completion:nil]; [self presentViewController:vc animated:YES completion:nil];
} }
- (void)handleIssueTap:(UITapGestureRecognizer *)gesture { - (void)handleIssueTap:(UITapGestureRecognizer *)gesture {
UIView *tappedCard = gesture.view; UIView *tappedCard = gesture.view;
NSDictionary *issueData = objc_getAssociatedObject(tappedCard, "issueData"); NSDictionary *issueData = objc_getAssociatedObject(tappedCard, "issueData");
......
// DrawerController.m // DrawerController.m
#import "DrawerController.h" #import "DrawerController.h"
#import "ProjectViewController.h" #import "ProjectViewController.h"
#import "DrawerViewController.h"
NSString * const DrawerDidSelectItemNotification = @"DrawerDidSelectItemNotification"; NSString * const DrawerDidSelectItemNotification = @"DrawerDidSelectItemNotification";
@interface DrawerController () <UIGestureRecognizerDelegate> @interface DrawerController () <UIGestureRecognizerDelegate>
@property (nonatomic, strong) ProjectViewController *mainVC; @property (nonatomic, strong) UIViewController *mainVC;
@property (nonatomic, strong) UINavigationController *mainNav;
@property (nonatomic, strong) UIViewController *drawerVC; @property (nonatomic, strong) UIViewController *drawerVC;
@property (nonatomic, strong) UIView *overlayView; @property (nonatomic, strong) UIView *overlayView;
@property (nonatomic, assign) BOOL drawerOpen; @property (nonatomic, assign) BOOL drawerOpen;
...@@ -27,12 +29,14 @@ NSString * const DrawerDidSelectItemNotification = @"DrawerDidSelectItemNotifica ...@@ -27,12 +29,14 @@ NSString * const DrawerDidSelectItemNotification = @"DrawerDidSelectItemNotifica
if (!self) return nil; if (!self) return nil;
// 1️⃣ Initialize DashboardViewController with props // 1️⃣ Initialize DashboardViewController with props
_mainVC = [[ProjectViewController alloc] initWithClientID:clientID ProjectViewController *rootVC = [[ProjectViewController alloc] initWithClientID:clientID
clientCode:clientCode clientCode:clientCode
userToken:user_token]; userToken:user_token];
// 2️⃣ Set back-reference to drawerController // 2️⃣ Set back-reference to drawerController
_mainVC.drawerController = self; rootVC.drawerController = self;
_mainNav = [[UINavigationController alloc] initWithRootViewController:rootVC];
_mainVC = _mainNav;
// 3️⃣ Save props locally // 3️⃣ Save props locally
_ClientID = [clientID copy]; _ClientID = [clientID copy];
...@@ -41,6 +45,11 @@ NSString * const DrawerDidSelectItemNotification = @"DrawerDidSelectItemNotifica ...@@ -41,6 +45,11 @@ NSString * const DrawerDidSelectItemNotification = @"DrawerDidSelectItemNotifica
// 4️⃣ Set drawer VC and drawer width // 4️⃣ Set drawer VC and drawer width
_drawerVC = drawer; _drawerVC = drawer;
if ([_drawerVC isKindOfClass:[DrawerViewController class]]) {
[(DrawerViewController *)_drawerVC attachDrawerController:self];
}
_drawerWidth = MIN([UIScreen mainScreen].bounds.size.width * 0.78, 360); _drawerWidth = MIN([UIScreen mainScreen].bounds.size.width * 0.78, 360);
return self; return self;
......
// DrawerViewController.h // DrawerViewController.h
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#import "DrawerController.h"
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
...@@ -10,7 +11,9 @@ NS_ASSUME_NONNULL_BEGIN ...@@ -10,7 +11,9 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, strong) NSString *profileEmail; @property (nonatomic, strong) NSString *profileEmail;
@property (nonatomic, strong) NSURL *profileImageURL; @property (nonatomic, strong) NSURL *profileImageURL;
@property (nonatomic, strong) NSArray<NSDictionary *> *menuItems; // array of { @"title":..., @"action":... } @property (nonatomic, strong) NSArray<NSDictionary *> *menuItems; // array of { @"title":..., @"action":... }
@property (nonatomic, weak, readonly) DrawerController *drawerController;
- (void)attachDrawerController:(DrawerController *)drawerController;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END
...@@ -190,7 +190,7 @@ ...@@ -190,7 +190,7 @@
#pragma mark - Back #pragma mark - Back
- (void)onBack { - (void)onBack {
[self dismissViewControllerAnimated:YES completion:nil]; [self.navigationController popViewControllerAnimated:YES];
} }
@end @end
// NotificationViewController.h // NotificationViewController.h
#import "DrawerController.h"
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@interface NotificationViewController : UIViewController @interface NotificationViewController : UIViewController
@property (nonatomic, weak) DrawerController *drawerController;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END
...@@ -3,6 +3,12 @@ ...@@ -3,6 +3,12 @@
#import "NotificationViewController.h" #import "NotificationViewController.h"
#import "APIClient.h" #import "APIClient.h"
#import "ImageCacheHelper.h" #import "ImageCacheHelper.h"
#import <objc/runtime.h>
#import "APIConfig.h"
#import "AppointmentDetailsViewController.h"
#import "DashboardViewController.h"
static char kNotificationKey;
@interface NotificationViewController () @interface NotificationViewController ()
// Header (existing) // Header (existing)
...@@ -15,6 +21,7 @@ ...@@ -15,6 +21,7 @@
@property (nonatomic, strong) UIStackView *stackView; @property (nonatomic, strong) UIStackView *stackView;
@property (nonatomic, strong) NSArray *notifications; @property (nonatomic, strong) NSArray *notifications;
@property (nonatomic, strong) NSArray *projectList; @property (nonatomic, strong) NSArray *projectList;
@property (nonatomic, strong) NSString *oldUnitId;
@end @end
@implementation NotificationViewController @implementation NotificationViewController
...@@ -22,6 +29,9 @@ ...@@ -22,6 +29,9 @@
- (void)viewDidLoad { - (void)viewDidLoad {
[super viewDidLoad]; [super viewDidLoad];
self.view.backgroundColor = UIColor.whiteColor; self.view.backgroundColor = UIColor.whiteColor;
if (self.oldUnitId) {
[APIConfig setDrawingPlanId:self.oldUnitId];
}
[self requestProjectList]; [self requestProjectList];
[self setupHeader]; [self setupHeader];
...@@ -157,7 +167,6 @@ ...@@ -157,7 +167,6 @@
[card addGestureRecognizer:tap]; [card addGestureRecognizer:tap];
card.userInteractionEnabled = YES; card.userInteractionEnabled = YES;
UIImageView *icon = [[UIImageView alloc] init]; UIImageView *icon = [[UIImageView alloc] init];
icon.translatesAutoresizingMaskIntoConstraints = NO; icon.translatesAutoresizingMaskIntoConstraints = NO;
icon.contentMode = UIViewContentModeScaleAspectFit; icon.contentMode = UIViewContentModeScaleAspectFit;
...@@ -172,15 +181,12 @@ ...@@ -172,15 +181,12 @@
icon.image = image; icon.image = image;
UIImage *img = image; UIImage *img = image;
icon.image = img; icon.image = img;
// Remove old aspect ratio if exists
for (NSLayoutConstraint *c in icon.constraints) { for (NSLayoutConstraint *c in icon.constraints) {
if (c.firstAttribute == NSLayoutAttributeHeight && if (c.firstAttribute == NSLayoutAttributeHeight &&
c.secondAttribute == NSLayoutAttributeWidth) { c.secondAttribute == NSLayoutAttributeWidth) {
[icon removeConstraint:c]; [icon removeConstraint:c];
} }
} }
CGFloat ratio = img.size.height / img.size.width; CGFloat ratio = img.size.height / img.size.width;
NSLayoutConstraint *aspect = NSLayoutConstraint *aspect =
...@@ -266,6 +272,11 @@ ...@@ -266,6 +272,11 @@
BOOL unread = [item[@"read_status"] isEqualToString:@"0"]; BOOL unread = [item[@"read_status"] isEqualToString:@"0"];
unreadDot.hidden = !unread; unreadDot.hidden = !unread;
objc_setAssociatedObject(card,
&kNotificationKey,
item,
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
return card; return card;
} }
...@@ -291,7 +302,7 @@ ...@@ -291,7 +302,7 @@
#pragma mark - helpers #pragma mark - helpers
- (void)onBack { - (void)onBack {
[self dismissViewControllerAnimated:YES completion:nil]; [self.navigationController popViewControllerAnimated:YES];
} }
- (void)requestNotification { - (void)requestNotification {
...@@ -399,22 +410,158 @@ ...@@ -399,22 +410,158 @@
} }
- (void)onNotificationTap:(UITapGestureRecognizer *)tap { - (void)onNotificationTap:(UITapGestureRecognizer *)tap {
NSLog(@"notification tapped");
UIView *card = tap.view; UIView *card = tap.view;
// NSDictionary *item = NSDictionary *item =
// objc_getAssociatedObject(card, @"notification"); objc_getAssociatedObject(card, &kNotificationKey);
// if (!item) return;
// if (!item) return;
// NSString *notificationType = item[@"type"];
// NSString *type = item[@"type"]; NSDictionary *strData = item;
// self.oldUnitId = [APIConfig drawingPlanId];
// if ([type isEqualToString:@"appointment_reminder"]) {
// [self openAppointment:item]; NSString *unitID = @"";
// } else if ([type isEqualToString:@"rectification"]) { if (strData[@"draw_plan_id"]) {
// [self openRectification:item]; unitID = strData[@"draw_plan_id"];
// } else { [APIConfig setDrawingPlanId:unitID];
// [self openGenericNotification:item]; }
// }
// ---- PAYMENT REMINDER ----
if ([notificationType isEqualToString:@"payment_reminder"]) {
NSLog(@"➡️ payment_reminder tapped");
return;
}
// ---- APPOINTMENT ----
if ([notificationType isEqualToString:@"appointment_reminder"] ||
[notificationType isEqualToString:@"unattend_appt_reminder"]) {
NSString *appointmentID = @"";
if (strData[@"appointment_id"]) {
appointmentID = strData[@"appointment_id"];
}
[self openAppointmentWithUnit:unitID appointmentID:appointmentID];
return;
}
// ---- CLEARANCE LETTER ----
if ([notificationType isEqualToString:@"clearance_letter"]) {
NSString *projectID = @"";
if (strData[@"project_id"]) {
projectID = strData[@"project_id"];
}
[self openClearanceWithProject:projectID unitID:unitID];
return;
}
// ---- DEFAULT: ISSUE FLOW ----
NSString *issueID = @"";
if (strData[@"issue_id"]) {
issueID = strData[@"issue_id"];
}
[self openIssueWithUnit:unitID issueID:issueID];
}
#pragma mark - Navigation (ported from RN)
- (void)openAppointmentWithUnit:(NSString *)unitID appointmentID:(NSString *)appointmentID {
NSLog(@"➡️ Open Appointment | unit=%@ appt=%@", unitID, appointmentID);
[APIClient requestDashboardInfo:^(BOOL success, NSDictionary * _Nullable data, NSError * _Nonnull error) {
if (!success || !data) {
return;
}
id appointment = data[@"Data"][@"appointment"];
if (!appointment ||
appointment == [NSNull null] ||
![appointment isKindOfClass:[NSArray class]] ||
appointmentID.length == 0) {
return;
}
NSDictionary *matchedAppointment = nil;
for (NSDictionary *appt in appointment) {
if (![appt isKindOfClass:[NSDictionary class]]) {
continue;
}
NSString *apptID = appt[@"id"];
if ([apptID isKindOfClass:[NSString class]] &&
[apptID isEqualToString:appointmentID]) {
matchedAppointment = appt;
break;
}
}
if (!matchedAppointment) {
// No match found
return;
}
// 👉 Navigate to Appointment Details
dispatch_async(dispatch_get_main_queue(), ^{
AppointmentDetailsViewController *vc = [[AppointmentDetailsViewController alloc] init];
vc.modalPresentationStyle = UIModalPresentationFullScreen;
vc.appointmentData = matchedAppointment;
[self presentViewController:vc animated:YES completion:nil];
});
}];
}
- (void)openClearanceWithProject:(NSString *)projectID unitID:(NSString *)unitID {
NSLog(@"➡️ Open Clearance | project=%@ unit=%@", projectID, unitID);
NSArray *projects = self.projectList;
if (!projects || projects.count == 0) {
NSLog(@"❌ Project list empty");
return;
}
for (NSDictionary *project in projects) {
if (![project isKindOfClass:[NSDictionary class]]) continue;
NSString *projID = [NSString stringWithFormat:@"%@", project[@"id"]];
if (![projID isEqualToString:projectID]) continue;
NSArray *units = project[@"unit"];
if (![units isKindOfClass:[NSArray class]]) break;
for (NSDictionary *unit in units) {
if (![unit isKindOfClass:[NSDictionary class]]) continue;
NSString *uID = [NSString stringWithFormat:@"%@", unit[@"id"]];
if (![uID isEqualToString:unitID]) continue;
NSLog(@"✅ Found project %@ and unit %@", projectID, unitID);
dispatch_async(dispatch_get_main_queue(), ^{
DashboardViewController *vc = [[DashboardViewController alloc] init];
vc.projectCode = unit[@"name"] ?: @"";
vc.projectName = project[@"project_name"] ?: @"";
vc.projectId = projectID ?: @"";
vc.drawingPlanId = unitID ?: @"";
vc.projectLogo = project[@"logo"] ?: @"";
vc.lotId = unit[@"lot_id"] ?: @"";
vc.drawerController = self.drawerController;
vc.modalPresentationStyle = UIModalPresentationFullScreen;
[self.navigationController pushViewController:vc animated:YES];
});
return;
}
}
NSLog(@"❌ No matching project/unit found");
}
- (void)openIssueWithUnit:(NSString *)unitID issueID:(NSString *)issueID {
NSLog(@"➡️ Open Issue | unit=%@ issue=%@", unitID, issueID);
// TODO: push IssueDetailViewController
} }
@end @end
...@@ -447,7 +447,7 @@ static NSString * const kLastOfflineSyncDateKey = @"LAST_OFFLINE_SYNC_DATE"; ...@@ -447,7 +447,7 @@ static NSString * const kLastOfflineSyncDateKey = @"LAST_OFFLINE_SYNC_DATE";
#pragma mark - Helpers #pragma mark - Helpers
- (void)onBack { - (void)onBack {
[self dismissViewControllerAnimated:YES completion:nil]; [self.navigationController popViewControllerAnimated:YES];
} }
- (void)addTapToCard:(UIView *)card action:(SEL)selector { - (void)addTapToCard:(UIView *)card action:(SEL)selector {
......
...@@ -100,6 +100,12 @@ NS_ASSUME_NONNULL_BEGIN ...@@ -100,6 +100,12 @@ NS_ASSUME_NONNULL_BEGIN
+ (void)requestAnnouncement:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion; + (void)requestAnnouncement:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion;
+ (void)uploadProfileImage:(NSData *)imageData
name:(NSString *)name
completion:(void(^)(BOOL success,
NSDictionary * _Nullable response,
NSError * _Nullable error))completion;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END
...@@ -2320,6 +2320,101 @@ ...@@ -2320,6 +2320,101 @@
[task resume]; [task resume];
} }
+ (void)uploadProfileImage:(NSData *)imageData
name:(NSString *)name
completion:(void(^)(BOOL success,
NSDictionary * _Nullable response,
NSError * _Nullable error))completion {
NSURL *url = [APIConfig urlWithPath:@"/framework/owner/auth/editUser"];
NSString *boundary = @"----ProfileImageBoundary";
NSMutableData *body = [NSMutableData data];
void (^appendString)(NSString *) = ^(NSString *string) {
[body appendData:[string dataUsingEncoding:NSUTF8StringEncoding]];
};
// name
appendString([NSString stringWithFormat:@"--%@\r\n", boundary]);
appendString(@"Content-Disposition: form-data; name=\"data[name]\"\r\n\r\n");
appendString(name ?: @"");
appendString(@"\r\n");
// language
appendString([NSString stringWithFormat:@"--%@\r\n", boundary]);
appendString(@"Content-Disposition: form-data; name=\"data[language]\"\r\n\r\n");
appendString(@"2");
appendString(@"\r\n");
// os
appendString([NSString stringWithFormat:@"--%@\r\n", boundary]);
appendString(@"Content-Disposition: form-data; name=\"data[os]\"\r\n\r\n");
appendString([APIConfig os]);
appendString(@"\r\n");
// information
appendString([NSString stringWithFormat:@"--%@\r\n", boundary]);
appendString(@"Content-Disposition: form-data; name=\"data[information]\"\r\n\r\n");
NSDictionary *info = [APIConfig deviceInfo];
NSData *jsonData =
[NSJSONSerialization dataWithJSONObject:info options:0 error:nil];
NSString *infoString =
[[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
appendString(infoString ?: @"");
appendString(@"\r\n");
// avatar
if (imageData) {
appendString([NSString stringWithFormat:@"--%@\r\n", boundary]);
appendString(@"Content-Disposition: form-data; name=\"data[avatar]\"; filename=\"profile.jpg\"\r\n");
appendString(@"Content-Type: image/jpeg\r\n\r\n");
[body appendData:imageData];
appendString(@"\r\n");
}
appendString([NSString stringWithFormat:@"--%@--\r\n", boundary]);
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
[request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary]
forHTTPHeaderField:@"Content-Type"];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
request.HTTPBody = body;
NSLog(@"🌍 upload profile image: %@", url.absoluteString);
NSURLSessionDataTask *task =
[[NSURLSession sharedSession] dataTaskWithRequest:request
completionHandler:^(NSData *data,
NSURLResponse *response,
NSError *error) {
if (error) {
dispatch_async(dispatch_get_main_queue(), ^{
completion(NO, nil, error);
});
return;
}
NSError *parseError;
NSDictionary *json =
[NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
dispatch_async(dispatch_get_main_queue(), ^{
if (parseError) {
completion(NO, nil, parseError);
} else {
completion(YES, json, nil);
}
});
}];
[task resume];
}
+ (void)requestNotification:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion { + (void)requestNotification:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion {
if ([APIConfig handleOfflineForAPI:@"Notification" completion:completion]) { if ([APIConfig handleOfflineForAPI:@"Notification" completion:completion]) {
...@@ -2395,6 +2490,7 @@ ...@@ -2395,6 +2490,7 @@
} }
// NSURL *url = [APIConfig urlWithPath:@"/announcement"]; // NSURL *url = [APIConfig urlWithPath:@"/announcement"];
//place holder, need to change back eventually
NSURL *url = [NSURL URLWithString:@"https://kitadev.commudesk.com/api/announcement?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6ImF0aGlyYWh6YWlkaUBjb252ZXAuY29tIiwicGFzc3dvcmQiOiIkMnkkMTAkNU9xYklqMnZ6UHJwckJrcVd5c3I2LmJCc1hVYS9Hd014eUhnL3RhUUhPUkNQcGdmTG8yakciLCJzdWIiOjIxNzAsImlzcyI6Imh0dHBzOi8va2l0YWRldi5jb21tdWRlc2suY29tL2FwaS9vd25lci9hdXRoL3Bhc3N3b3JkbGVzc19sb2dpbiIsImlhdCI6MTc2MDMxNTM1MiwiZXhwIjoyMDc1ODg0ODcyLCJuYmYiOjE3NjAzMTUzNTIsImp0aSI6IktoQmNyQnJEdDVNdDZlWmMifQ.JnxGbZ7hTeoOr6oibIzZMphgyKtTo2Aq9Efx6mrGfFA"]; NSURL *url = [NSURL URLWithString:@"https://kitadev.commudesk.com/api/announcement?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6ImF0aGlyYWh6YWlkaUBjb252ZXAuY29tIiwicGFzc3dvcmQiOiIkMnkkMTAkNU9xYklqMnZ6UHJwckJrcVd5c3I2LmJCc1hVYS9Hd014eUhnL3RhUUhPUkNQcGdmTG8yakciLCJzdWIiOjIxNzAsImlzcyI6Imh0dHBzOi8va2l0YWRldi5jb21tdWRlc2suY29tL2FwaS9vd25lci9hdXRoL3Bhc3N3b3JkbGVzc19sb2dpbiIsImlhdCI6MTc2MDMxNTM1MiwiZXhwIjoyMDc1ODg0ODcyLCJuYmYiOjE3NjAzMTUzNTIsImp0aSI6IktoQmNyQnJEdDVNdDZlWmMifQ.JnxGbZ7hTeoOr6oibIzZMphgyKtTo2Aq9Efx6mrGfFA"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
......
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