Commit 227d7a6d authored by Wei Han's avatar Wei Han

side menu code update

parent 1323f31a
......@@ -73,7 +73,6 @@
//[[OfflineSyncManager shared] clearOfflineQueue];
[[NSNotificationCenter defaultCenter] postNotificationName:@"ShowHiddenButtonNotification" object:@(YES)];
}
- (void)viewWillAppear:(BOOL)animated {
......@@ -82,11 +81,13 @@
NSLog(@"Dashboard loaded, refreshing data");
[self refreshDashboardContent];
self.navigationController.navigationBarHidden = YES;
[[NSNotificationCenter defaultCenter] postNotificationName:@"ShowHiddenButtonNotification" object:@(YES)];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
self.navigationController.navigationBarHidden = YES;
[[NSNotificationCenter defaultCenter] postNotificationName:@"ShowHiddenButtonNotification" object:@(NO)];
}
#pragma mark - Refresh Logic
......
......@@ -146,7 +146,6 @@ static NSString * const ProfileDidUpdateNotification = @"ProfileDidUpdateNotific
- (void)loadDefaultsIfNeeded {
if (!self.profileName) self.profileName = @"Guest User";
if (!self.profileEmail) self.profileEmail = @"guest@example.com";
if (!self.profileImageURL) self.profileImageURL = nil;
self.nameLabel.text = self.profileName;
self.emailLabel.text = self.profileEmail;
......
// ManageAccountViewController.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface ManageAccountViewController : UIViewController
@property (nonatomic, strong) NSArray<NSDictionary *> *accounts;
@end
NS_ASSUME_NONNULL_END
// ManageAccountViewController.mm
#import "ManageAccountViewController.h"
@interface ManageAccountViewController () <UITableViewDelegate, UITableViewDataSource>
// Header
@property (nonatomic, strong) UIView *headerBar;
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UIButton *backButton;
// Table
@property (nonatomic, strong) UITableView *accountTable;
@property (nonatomic, strong) UIView *dimmedOverlay;
@property (nonatomic, strong) UIView *addLinkSheet;
@property (nonatomic, strong) UIView *footerView;
@end
@implementation ManageAccountViewController
#pragma mark - Init with accounts
- (instancetype)initWithAccounts:(NSArray<NSDictionary *> *)accounts {
self = [super init];
if (self) {
_accounts = accounts;
}
return self;
}
#pragma mark - View Lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = UIColor.whiteColor;
[self setupHeader];
[self setupFooter];
[self setupTable];
}
#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 = @"Manage Accounts";
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 - Table
- (void)setupTable {
self.accountTable = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
self.accountTable.delegate = self;
self.accountTable.dataSource = self;
self.accountTable.rowHeight = UITableViewAutomaticDimension;
self.accountTable.estimatedRowHeight = 110;
self.accountTable.tableFooterView = [UIView new];
self.accountTable.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.accountTable];
[NSLayoutConstraint activateConstraints:@[
[self.accountTable.topAnchor constraintEqualToAnchor:self.headerBar.bottomAnchor],
[self.accountTable.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.accountTable.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.accountTable.bottomAnchor constraintEqualToAnchor:self.footerView.topAnchor],
]];
}
#pragma mark - Table DataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.accounts.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSDictionary *account = self.accounts[indexPath.row];
return [self accountCellForTable:tableView atIndexPath:indexPath withData:account];
}
#pragma mark - Table Cell Setup
- (UITableViewCell *)accountCellForTable:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath withData:(NSDictionary *)account {
static NSString *cellId = @"AccountCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];
[self setupAccountCellSubviews:cell];
}
[self configureAccountCell:cell withData:account];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
- (void)setupAccountCellSubviews:(UITableViewCell *)cell {
UIImageView *profileImageView = [[UIImageView alloc] init];
profileImageView.tag = 1000;
profileImageView.layer.cornerRadius = 20;
profileImageView.clipsToBounds = YES;
profileImageView.backgroundColor = UIColor.systemGray4Color;
profileImageView.translatesAutoresizingMaskIntoConstraints = NO;
[cell.contentView addSubview:profileImageView];
UILabel *nameLabel = [[UILabel alloc] init];
nameLabel.tag = 1001;
nameLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightSemibold];
nameLabel.translatesAutoresizingMaskIntoConstraints = NO;
UILabel *companyLabel = [[UILabel alloc] init];
companyLabel.tag = 1002;
companyLabel.font = [UIFont systemFontOfSize:13];
companyLabel.textColor = UIColor.systemGrayColor;
companyLabel.translatesAutoresizingMaskIntoConstraints = NO;
UILabel *dotLabel = [[UILabel alloc] init];
dotLabel.text = @"·";
dotLabel.tag = 1003;
dotLabel.font = [UIFont systemFontOfSize:13];
dotLabel.textColor = UIColor.systemGray3Color;
dotLabel.translatesAutoresizingMaskIntoConstraints = NO;
UILabel *userLabel = [[UILabel alloc] init];
userLabel.tag = 1004;
userLabel.font = [UIFont systemFontOfSize:13];
userLabel.textColor = UIColor.systemGrayColor;
userLabel.translatesAutoresizingMaskIntoConstraints = NO;
for (UIView *sub in @[nameLabel, companyLabel, dotLabel, userLabel]) {
[cell.contentView addSubview:sub];
}
UIButton *deleteButton = [UIButton buttonWithType:UIButtonTypeSystem];
[deleteButton setTitle:@"Remove from Device" forState:UIControlStateNormal];
[deleteButton setTitleColor:UIColor.systemRedColor forState:UIControlStateNormal];
deleteButton.tintColor = UIColor.systemRedColor;
deleteButton.layer.borderWidth = 0.5;
deleteButton.layer.borderColor = UIColor.systemRedColor.CGColor;
deleteButton.layer.cornerRadius = 12;
deleteButton.titleLabel.font = [UIFont systemFontOfSize:13 weight:UIFontWeightRegular];
deleteButton.translatesAutoresizingMaskIntoConstraints = NO;
deleteButton.tag = 1005;
[deleteButton addTarget:self action:@selector(deleteButtonTapped:)
forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:deleteButton];
[NSLayoutConstraint activateConstraints:@[
[profileImageView.leadingAnchor constraintEqualToAnchor:cell.contentView.leadingAnchor constant:16],
[profileImageView.topAnchor constraintEqualToAnchor:cell.contentView.topAnchor constant:16],
[profileImageView.widthAnchor constraintEqualToConstant:40],
[profileImageView.heightAnchor constraintEqualToConstant:40],
[nameLabel.topAnchor constraintEqualToAnchor:cell.contentView.topAnchor constant:16],
[nameLabel.leadingAnchor constraintEqualToAnchor:profileImageView.trailingAnchor constant:12],
[nameLabel.trailingAnchor constraintLessThanOrEqualToAnchor:cell.contentView.trailingAnchor constant:-16],
[companyLabel.topAnchor constraintEqualToAnchor:nameLabel.bottomAnchor constant:4],
[companyLabel.leadingAnchor constraintEqualToAnchor:nameLabel.leadingAnchor],
[dotLabel.centerYAnchor constraintEqualToAnchor:companyLabel.centerYAnchor],
[dotLabel.leadingAnchor constraintEqualToAnchor:companyLabel.trailingAnchor constant:6],
[userLabel.centerYAnchor constraintEqualToAnchor:companyLabel.centerYAnchor],
[userLabel.leadingAnchor constraintEqualToAnchor:dotLabel.trailingAnchor constant:6],
[userLabel.trailingAnchor constraintLessThanOrEqualToAnchor:cell.contentView.trailingAnchor constant:-16],
[deleteButton.topAnchor constraintEqualToAnchor:userLabel.bottomAnchor constant:12],
[deleteButton.trailingAnchor constraintEqualToAnchor:cell.contentView.trailingAnchor constant:-16],
[deleteButton.leadingAnchor constraintEqualToAnchor:cell.contentView.leadingAnchor constant:16],
[deleteButton.heightAnchor constraintEqualToConstant:36],
[deleteButton.bottomAnchor constraintEqualToAnchor:cell.contentView.bottomAnchor constant:-12], // ⭐ THIS
]];
}
- (void)configureAccountCell:(UITableViewCell *)cell withData:(NSDictionary *)account {
UILabel *nameLabel = [cell.contentView viewWithTag:1001];
UILabel *companyLabel = [cell.contentView viewWithTag:1002];
UILabel *userLabel = [cell.contentView viewWithTag:1004];
nameLabel.text = account[@"name"];
companyLabel.text = account[@"company_code"];
userLabel.text = account[@"userName"];
}
- (void)deleteButtonTapped:(UIButton *)sender {
// Get the cell from the button
UITableViewCell *cell = (UITableViewCell *)sender.superview.superview;
NSIndexPath *indexPath = [self.accountTable indexPathForCell:cell];
if (indexPath) {
NSMutableArray *mutableAccounts = [self.accounts mutableCopy];
NSDictionary *deletedAccount = mutableAccounts[indexPath.row];
[mutableAccounts removeObjectAtIndex:indexPath.row];
self.accounts = [mutableAccounts copy];
// Animate deletion
[self.accountTable deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
NSLog(@"Deleted account: %@", deletedAccount[@"name"]);
}
}
#pragma mark - Footer Button
-(void)setupFooter {
self.footerView = [[UIView alloc] init];
self.footerView.backgroundColor = UIColor.clearColor;
[self.view addSubview:self.footerView];
self.footerView.translatesAutoresizingMaskIntoConstraints = NO;
[NSLayoutConstraint activateConstraints:@[
[self.footerView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.footerView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.footerView.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor],
[self.footerView.heightAnchor constraintEqualToConstant:64],
]];
UIButton *footerButton = [UIButton buttonWithType:UIButtonTypeSystem];
[footerButton setTitle:@"Add Account" forState:UIControlStateNormal];
footerButton.titleLabel.font = [UIFont boldSystemFontOfSize:16];
footerButton.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0];
footerButton.tintColor = UIColor.whiteColor;
footerButton.layer.cornerRadius = 12;
[footerButton addTarget:self action:@selector(addAccountsTapped)
forControlEvents:UIControlEventTouchUpInside];
[self.footerView addSubview:footerButton];
footerButton.translatesAutoresizingMaskIntoConstraints = NO;
[NSLayoutConstraint activateConstraints:@[
[footerButton.bottomAnchor constraintEqualToAnchor:self.footerView.safeAreaLayoutGuide.bottomAnchor],
[footerButton.centerXAnchor constraintEqualToAnchor:self.footerView.centerXAnchor],
[footerButton.heightAnchor constraintEqualToConstant:48],
[footerButton.leadingAnchor constraintEqualToAnchor:self.footerView.leadingAnchor constant:20],
[footerButton.trailingAnchor constraintEqualToAnchor:self.footerView.trailingAnchor constant:-20],
]];
}
#pragma mark - Add Account
- (void)dismissAddLinkSheet:(void(^)(void))completion {
[UIView animateWithDuration:0.3 animations:^{
self.addLinkSheet.transform = CGAffineTransformMakeTranslation(0, 300);
self.dimmedOverlay.alpha = 0;
} completion:^(BOOL finished) {
[self.addLinkSheet removeFromSuperview];
[self.dimmedOverlay removeFromSuperview];
if (completion) completion();
}];
}
- (void)dismissAddLinkSheetButtonTapped:(id)sender {
[self dismissAddLinkSheet:nil]; // no completion needed
}
- (UIView *)buildDimmedOverlay {
UIView *overlay = [[UIView alloc] initWithFrame:self.view.bounds];
overlay.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6];
overlay.alpha = 0;
overlay.userInteractionEnabled = YES;
// Tap to dismiss
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(dismissAddLinkSheetButtonTapped:)];
tap.cancelsTouchesInView = NO; // <-- allow touches to pass to sheet buttons
[overlay addGestureRecognizer:tap];
return overlay;
}
-(void)addAccountsTapped{
NSLog(@"Add Accounts Tapped");
[self dismissAddLinkSheet:^{
// now fully dismissed, safe to show new sheet
self.dimmedOverlay = [self buildDimmedOverlay];
self.addLinkSheet = [self addAccountSheet];
[self.view addSubview:self.dimmedOverlay];
[self.view addSubview:self.addLinkSheet];
NSLayoutConstraint *bottom = [self.addLinkSheet.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor constant:300];
bottom.active = YES;
[NSLayoutConstraint activateConstraints:@[
[self.addLinkSheet.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.addLinkSheet.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.addLinkSheet.heightAnchor constraintEqualToConstant:250],
]];
[self.view layoutIfNeeded];
[UIView animateWithDuration:0.3 animations:^{
self.dimmedOverlay.alpha = 1;
bottom.constant = 0;
[self.view layoutIfNeeded];
}];
}];
}
- (UIView *)addAccountSheet {
UIView *sheet = [[UIView alloc] init];
sheet.backgroundColor = UIColor.whiteColor;
sheet.layer.cornerRadius = 24;
sheet.layer.maskedCorners = kCALayerMinXMinYCorner | kCALayerMaxXMinYCorner;
sheet.translatesAutoresizingMaskIntoConstraints = NO;
UIView *header = [[UIView alloc] init];
header.translatesAutoresizingMaskIntoConstraints = NO;
[sheet addSubview:header];
UILabel *title = [[UILabel alloc] init];
title.text = @"Add Account";
title.font = [UIFont systemFontOfSize:18 weight:UIFontWeightBold];
title.translatesAutoresizingMaskIntoConstraints = NO;
// UIButton *closeButton = [UIButton buttonWithType:UIButtonTypeSystem];
// [closeButton setImage:[UIImage systemImageNamed:@"xmark"] forState:UIControlStateNormal];
// closeButton.tintColor = UIColor.systemGrayColor;
// [closeButton addTarget:self action:@selector(dismissAddLinkSheetButtonTapped:)
// forControlEvents:UIControlEventTouchUpInside];
// closeButton.translatesAutoresizingMaskIntoConstraints = NO;
[header addSubview:title];
// [header addSubview:closeButton];
UILabel *subtitle = [[UILabel alloc] init];
subtitle.text = @"Select an option to proceed.";
subtitle.font = [UIFont systemFontOfSize:14];
subtitle.textAlignment = NSTextAlignmentLeft;
subtitle.numberOfLines = 0;
subtitle.textColor = UIColor.darkGrayColor;
subtitle.translatesAutoresizingMaskIntoConstraints = NO;
[sheet addSubview:subtitle];
UIView *spacer1 = [[UIView alloc] init];
spacer1.translatesAutoresizingMaskIntoConstraints = NO;
spacer1.layer.borderWidth = 0.5;
spacer1.layer.borderColor = [UIColor lightGrayColor].CGColor;
[sheet addSubview:spacer1];
// --- Existing Account ---
UIView *existingAccount = [[UIView alloc] init];
existingAccount.translatesAutoresizingMaskIntoConstraints = NO;
[sheet addSubview:existingAccount];
UILabel *existingTitle = [[UILabel alloc] init];
existingTitle.text = @"Add Existing Account";
existingTitle.font = [UIFont systemFontOfSize:16 weight:UIFontWeightBold];
existingTitle.translatesAutoresizingMaskIntoConstraints = NO;
UIButton *existingButton = [UIButton buttonWithType:UIButtonTypeSystem];
[existingButton setImage:[UIImage systemImageNamed:@"plus"] forState:UIControlStateNormal];
existingButton.tintColor = UIColor.systemGrayColor;
[existingButton addTarget:self action:@selector(existingButtonTapped)
forControlEvents:UIControlEventTouchUpInside];
existingButton.translatesAutoresizingMaskIntoConstraints = NO;
[existingAccount addSubview:existingTitle];
[existingAccount addSubview:existingButton];
UIView *spacer2 = [[UIView alloc] init];
spacer2.translatesAutoresizingMaskIntoConstraints = NO;
spacer2.layer.borderWidth = 0.5;
spacer2.layer.borderColor = [UIColor lightGrayColor].CGColor;
[sheet addSubview:spacer2];
// --- New Account ---
UIView *newAccount = [[UIView alloc] init];
newAccount.translatesAutoresizingMaskIntoConstraints = NO;
[sheet addSubview:newAccount];
UILabel *newTitle = [[UILabel alloc] init];
newTitle.text = @"Add New Account";
newTitle.font = [UIFont systemFontOfSize:16 weight:UIFontWeightBold];
newTitle.translatesAutoresizingMaskIntoConstraints = NO;
UIButton *newButton = [UIButton buttonWithType:UIButtonTypeSystem];
[newButton setImage:[UIImage systemImageNamed:@"plus"] forState:UIControlStateNormal];
newButton.tintColor = UIColor.systemGrayColor;
[newButton addTarget:self action:@selector(newButtonTapped)
forControlEvents:UIControlEventTouchUpInside];
newButton.translatesAutoresizingMaskIntoConstraints = NO;
[newAccount addSubview:newTitle];
[newAccount addSubview:newButton];
[NSLayoutConstraint activateConstraints:@[
[header.topAnchor constraintEqualToAnchor:sheet.topAnchor constant:24],
[header.leadingAnchor constraintEqualToAnchor:sheet.leadingAnchor constant:20],
[header.trailingAnchor constraintEqualToAnchor:sheet.trailingAnchor constant:-20],
[title.leadingAnchor constraintEqualToAnchor:header.leadingAnchor],
[title.topAnchor constraintEqualToAnchor:header.topAnchor],
// [closeButton.trailingAnchor constraintEqualToAnchor:header.trailingAnchor],
// [closeButton.centerYAnchor constraintEqualToAnchor:title.centerYAnchor],
// [closeButton.heightAnchor constraintEqualToConstant:24],
// [closeButton.widthAnchor constraintEqualToConstant:24],
[subtitle.topAnchor constraintEqualToAnchor:title.bottomAnchor constant:12],
[subtitle.leadingAnchor constraintEqualToAnchor:sheet.leadingAnchor constant:20],
[subtitle.trailingAnchor constraintEqualToAnchor:sheet.trailingAnchor constant:-20],
[spacer1.topAnchor constraintEqualToAnchor:subtitle.bottomAnchor constant:20],
[spacer1.leadingAnchor constraintEqualToAnchor:sheet.leadingAnchor],
[spacer1.trailingAnchor constraintEqualToAnchor:sheet.trailingAnchor],
[spacer1.heightAnchor constraintEqualToConstant:1],
[existingAccount.topAnchor constraintEqualToAnchor:spacer1.bottomAnchor constant:20],
[existingAccount.leadingAnchor constraintEqualToAnchor:sheet.leadingAnchor constant:16],
[existingAccount.trailingAnchor constraintEqualToAnchor:sheet.trailingAnchor constant:-16],
[existingTitle.topAnchor constraintEqualToAnchor:existingAccount.topAnchor],
[existingTitle.leadingAnchor constraintEqualToAnchor:existingAccount.leadingAnchor],
[existingTitle.trailingAnchor constraintEqualToAnchor:existingButton.leadingAnchor constant:-16],
[existingButton.centerYAnchor constraintEqualToAnchor:existingTitle.centerYAnchor],
[existingButton.trailingAnchor constraintEqualToAnchor:existingAccount.trailingAnchor],
[existingButton.heightAnchor constraintEqualToConstant:24],
[existingButton.widthAnchor constraintEqualToConstant:24],
[spacer2.topAnchor constraintEqualToAnchor:existingButton.bottomAnchor constant:18],
[spacer2.leadingAnchor constraintEqualToAnchor:sheet.leadingAnchor constant:16],
[spacer2.trailingAnchor constraintEqualToAnchor:sheet.trailingAnchor constant:-16],
[spacer2.heightAnchor constraintEqualToConstant:1],
[newAccount.topAnchor constraintEqualToAnchor:spacer2.bottomAnchor constant:18],
[newAccount.leadingAnchor constraintEqualToAnchor:sheet.leadingAnchor constant:16],
[newAccount.trailingAnchor constraintEqualToAnchor:sheet.trailingAnchor constant:-16],
[newTitle.topAnchor constraintEqualToAnchor:newAccount.topAnchor],
[newTitle.leadingAnchor constraintEqualToAnchor:newAccount.leadingAnchor],
[newTitle.trailingAnchor constraintEqualToAnchor:newButton.leadingAnchor constant:-16],
[newButton.centerYAnchor constraintEqualToAnchor:newTitle.centerYAnchor],
[newButton.trailingAnchor constraintEqualToAnchor:newAccount.trailingAnchor],
[newButton.heightAnchor constraintEqualToConstant:24],
[newButton.widthAnchor constraintEqualToConstant:24],
]];
return sheet;
}
-(void)existingButtonTapped{
NSLog(@"existing account button tapped");
}
-(void)newButtonTapped {
NSLog(@"new account button tapped");
}
@end
......@@ -7,6 +7,7 @@
#import "APIConfig.h"
#import "AppointmentDetailsViewController.h"
#import "DashboardViewController.h"
#import "IssueDetailViewController.h"
static char kNotificationKey;
......@@ -418,6 +419,8 @@ static char kNotificationKey;
NSString *notificationType = item[@"type"];
NSDictionary *strData = item;
self.oldUnitId = [APIConfig drawingPlanId];
NSString *projectName = item[@"project_name"];
NSString *projectCode = item[@"draw_plan_name"];
NSString *unitID = @"";
if (strData[@"draw_plan_id"]) {
......@@ -461,7 +464,7 @@ static char kNotificationKey;
issueID = strData[@"issue_id"];
}
[self openIssueWithUnit:unitID issueID:issueID];
[self openIssueWithUnit:unitID issueID:issueID projectName:projectName projectCode:projectCode];
}
......@@ -470,6 +473,7 @@ static char kNotificationKey;
NSLog(@"➡️ Open Appointment | unit=%@ appt=%@", unitID, appointmentID);
[APIClient requestDashboardInfo:^(BOOL success, NSDictionary * _Nullable data, NSError * _Nonnull error) {
if (!success || !data) {
[APIConfig setDrawingPlanId:self.oldUnitId];
return;
}
......@@ -479,6 +483,7 @@ static char kNotificationKey;
appointment == [NSNull null] ||
![appointment isKindOfClass:[NSArray class]] ||
appointmentID.length == 0) {
[APIConfig setDrawingPlanId:self.oldUnitId];
return;
}
......@@ -500,12 +505,14 @@ static char kNotificationKey;
}
if (!matchedAppointment) {
// No match found
NSLog(@"❌ No matching appointment found");
[APIConfig setDrawingPlanId:self.oldUnitId];
return;
}
// 👉 Navigate to Appointment Details
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"navigating to appointment details");
AppointmentDetailsViewController *vc = [[AppointmentDetailsViewController alloc] init];
vc.modalPresentationStyle = UIModalPresentationFullScreen;
vc.appointmentData = matchedAppointment;
......@@ -520,14 +527,17 @@ static char kNotificationKey;
NSArray *projects = self.projectList;
if (!projects || projects.count == 0) {
NSLog(@"❌ Project list empty");
[APIConfig setDrawingPlanId:self.oldUnitId];
return;
}
for (NSDictionary *project in projects) {
if (![project isKindOfClass:[NSDictionary class]]) continue;
NSString *projectIDStr = [NSString stringWithFormat:@"%@", projectID];
NSString *projID = [NSString stringWithFormat:@"%@", project[@"id"]];
if (![projID isEqualToString:projectID]) continue;
if (![projID isEqualToString:projectIDStr]) continue;
NSArray *units = project[@"unit"];
if (![units isKindOfClass:[NSArray class]]) break;
......@@ -536,7 +546,9 @@ static char kNotificationKey;
if (![unit isKindOfClass:[NSDictionary class]]) continue;
NSString *uID = [NSString stringWithFormat:@"%@", unit[@"id"]];
if (![uID isEqualToString:unitID]) continue;
NSString *unitIDStr = [NSString stringWithFormat:@"%@", unitID];
if (![uID isEqualToString:unitIDStr]) continue;
NSLog(@"uID: %@", uID);
NSLog(@"✅ Found project %@ and unit %@", projectID, unitID);
......@@ -556,12 +568,53 @@ static char kNotificationKey;
}
}
NSLog(@"❌ No matching project/unit found");
[APIConfig setDrawingPlanId:self.oldUnitId];
}
- (void)openIssueWithUnit:(NSString *)unitID issueID:(NSString *)issueID {
- (void)openIssueWithUnit:(NSString *)unitID issueID:(NSString *)issueID projectName:(NSString *)projectName projectCode:(NSString *)projectCode {
NSLog(@"➡️ Open Issue | unit=%@ issue=%@", unitID, issueID);
// TODO: push IssueDetailViewController
[APIClient requestIssues:^(BOOL success, NSDictionary * _Nullable data, NSError * _Nonnull error) {
if (!success || !data) {
[APIConfig setDrawingPlanId:self.oldUnitId];
return;
};
NSArray *issues = data[@"Data"];
if (!issues || ![issues isKindOfClass:[NSArray class]]) {
[APIConfig setDrawingPlanId:self.oldUnitId];
return;
}
NSDictionary *matchedIssue = nil;
for (NSDictionary *issue in issues) {
if (![issue isKindOfClass:[NSDictionary class]]) continue;
NSString *iID = [NSString stringWithFormat:@"%@", issue[@"id"]];
NSString *issueIDStr = [NSString stringWithFormat:@"%@", issueID];
if ([iID isEqualToString:issueIDStr]) {
matchedIssue = issue;
break;
}
}
if (!matchedIssue) {
[APIConfig setDrawingPlanId:self.oldUnitId];
NSLog(@"❌ No matching issue found");
return;
}
// 2️⃣ Navigate to Issue Detail
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"➡️ Navigating to IssueDetailViewController");
IssueDetailViewController *vc = [[IssueDetailViewController alloc] init];
vc.modalPresentationStyle = UIModalPresentationFullScreen;
vc.issueData = matchedIssue;
vc.projectCode = projectCode;
vc.projectName = projectName;
[self presentViewController:vc animated:YES completion:nil];
});
}];
}
@end
......@@ -4,8 +4,15 @@
#import "APIClient.h"
#import "ImageCacheHelper.h"
#import <Photos/Photos.h>
#import "ManageAccountViewController.h"
@interface ProfileViewController () <UIImagePickerControllerDelegate, UINavigationControllerDelegate, UIScrollViewDelegate>
typedef NS_ENUM(NSInteger, AppLanguage) {
AppLanguageMalay = 0,
AppLanguageEnglish = 1,
AppLanguageChinese = 2
};
@interface ProfileViewController () <UIImagePickerControllerDelegate, UINavigationControllerDelegate, UIScrollViewDelegate, UITableViewDelegate, UITableViewDataSource>
// Header
@property (nonatomic, strong) UIView *headerBar;
......@@ -48,6 +55,11 @@
@property (nonatomic, strong) UIView *imageViewer;
@property (nonatomic, strong) UIScrollView *imageScrollView;
@property (nonatomic, strong) UIImageView *fullscreenImageView;
@property (nonatomic, assign) NSInteger selectedLanguageIndex;
@property (nonatomic, strong) NSArray<UIControl *> *languageRows;
@property (nonatomic, assign) AppLanguage selectedLanguage;
@property (nonatomic, strong) UITableView *accountTable;
@property (nonatomic, strong) NSArray *accounts;
@end
......@@ -58,6 +70,7 @@
[super viewDidLoad];
self.view.backgroundColor = UIColor.systemBackgroundColor;
self.selectedLanguageIndex = 1; // English default
[self setupHeader];
[self setupScrollView];
[self setupProfile];
......@@ -460,7 +473,6 @@
return button;
}
#pragma mark - API
-(void) requestProfile {
[APIClient requestProfile:^(BOOL success, NSDictionary *data, NSError *error) {
......@@ -539,11 +551,8 @@
return view;
}
#pragma mark - Helpers
- (void)onBack {
[self dismissViewControllerAnimated:YES completion:nil];
}
#pragma mark - Logout & Delete Buttons
- (void)logoutTapped {
UIAlertController *alert =
[UIAlertController alertControllerWithTitle:@"Alert"
......@@ -603,7 +612,6 @@
- (void)performDeleteAccount {
// Example API call
[APIClient deleteProfile:^(BOOL success, NSDictionary *data, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (error || !success) {
......@@ -632,21 +640,23 @@
}];
}
#pragma mark - Add Link
#pragma mark - Edit Name
- (UIView *)buildDimmedOverlay {
UIView *overlay = [[UIView alloc] initWithFrame:self.view.bounds];
overlay.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6];
overlay.alpha = 0;
overlay.userInteractionEnabled = YES;
UITapGestureRecognizer *tap =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(dismissAddLinkSheet)];
// Tap to dismiss
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(dismissAddLinkSheetButtonTapped:)];
tap.cancelsTouchesInView = NO; // <-- allow touches to pass to sheet buttons
[overlay addGestureRecognizer:tap];
return overlay;
}
- (UIView *)buildAddLinkSheet {
- (UIView *)changeNameSheet {
UIView *sheet = [[UIView alloc] init];
sheet.backgroundColor = UIColor.whiteColor;
sheet.layer.cornerRadius = 24;
......@@ -715,8 +725,11 @@
}
- (void)editNamePressed {
[self.addLinkSheet removeFromSuperview];
[self.dimmedOverlay removeFromSuperview];
self.dimmedOverlay = [self buildDimmedOverlay];
self.addLinkSheet = [self buildAddLinkSheet];
self.addLinkSheet = [self changeNameSheet];
[self.view addSubview:self.dimmedOverlay];
[self.view addSubview:self.addLinkSheet];
......@@ -728,7 +741,6 @@
[NSLayoutConstraint activateConstraints:@[
[self.addLinkSheet.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.addLinkSheet.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.addLinkSheet.heightAnchor constraintEqualToConstant:320],
]];
[self.view layoutIfNeeded];
......@@ -740,17 +752,21 @@
}];
}
- (void)dismissAddLinkSheet {
[UIView animateWithDuration:0.25 animations:^{
self.dimmedOverlay.alpha = 0;
- (void)dismissAddLinkSheet:(void(^)(void))completion {
[UIView animateWithDuration:0.3 animations:^{
self.addLinkSheet.transform = CGAffineTransformMakeTranslation(0, 300);
self.dimmedOverlay.alpha = 0;
} completion:^(BOOL finished) {
[self.addLinkSheet removeFromSuperview];
[self.dimmedOverlay removeFromSuperview];
self.linkNameField.text = @"";
if (completion) completion();
}];
}
- (void)dismissAddLinkSheetButtonTapped:(id)sender {
[self dismissAddLinkSheet:nil]; // no completion needed
}
- (void)onTextChanged:(UITextField *)textField {
BOOL hasText = textField.text.length > 0;
self.createButton.enabled = hasText;
......@@ -759,6 +775,256 @@
: UIColor.systemGray5Color;
}
#pragma mark - Change Language
- (UIView *)buildLanguageSheet {
UIView *sheet = [[UIView alloc] init];
sheet.backgroundColor = UIColor.whiteColor;
sheet.layer.cornerRadius = 24;
sheet.layer.maskedCorners = kCALayerMinXMinYCorner | kCALayerMaxXMinYCorner;
sheet.translatesAutoresizingMaskIntoConstraints = NO;
UIView *header = [[UIView alloc] init];
header.translatesAutoresizingMaskIntoConstraints = NO;
[sheet addSubview:header];
UILabel *title = [[UILabel alloc] init];
title.text = @"Change Language";
title.font = [UIFont systemFontOfSize:20 weight:UIFontWeightBold];
title.translatesAutoresizingMaskIntoConstraints = NO;
// UIButton *closeButton = [UIButton buttonWithType:UIButtonTypeSystem];
// [closeButton setImage:[UIImage systemImageNamed:@"xmark"] forState:UIControlStateNormal];
// closeButton.tintColor = UIColor.systemGrayColor;
// [closeButton addTarget:self action:@selector(dismissAddLinkSheetButtonTapped:)
// forControlEvents:UIControlEventTouchUpInside];
// closeButton.translatesAutoresizingMaskIntoConstraints = NO;
[header addSubview:title];
// [header addSubview:closeButton];
UILabel *subtitle = [[UILabel alloc] init];
subtitle.text = @"You can change your preferred language listed below.";
subtitle.font = [UIFont systemFontOfSize:14];
subtitle.textAlignment = NSTextAlignmentLeft;
subtitle.numberOfLines = 0;
subtitle.textColor = UIColor.darkGrayColor;
subtitle.translatesAutoresizingMaskIntoConstraints = NO;
[sheet addSubview:subtitle];
// --- Language Buttons ---
UIControl *bm = [self languageRow:@"Bahasa Melayu" selected:NO tag:0];
UIControl *en = [self languageRow:@"English" selected:YES tag:1];
UIControl *zh = [self languageRow:@"中文" selected:NO tag:2];
UIView *sep1 = [self separatorView];
UIView *sep2 = [self separatorView];
self.languageRows = @[bm, en, zh];
self.selectedLanguage = AppLanguageEnglish;
[sheet addSubview:bm];
[sheet addSubview:sep1];
[sheet addSubview:en];
[sheet addSubview:sep2];
[sheet addSubview:zh];
//Ok Button
UIButton *okButton = [UIButton buttonWithType:UIButtonTypeSystem];
[okButton setTitle:@"OK" forState:UIControlStateNormal];
okButton.titleLabel.font = [UIFont systemFontOfSize:18 weight:UIFontWeightSemibold];
okButton.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0];
okButton.layer.cornerRadius = 26;
[okButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
[okButton addTarget:self action:@selector(confirmLanguage)
forControlEvents:UIControlEventTouchUpInside];
okButton.translatesAutoresizingMaskIntoConstraints = NO;
[sheet addSubview:okButton];
[NSLayoutConstraint activateConstraints:@[
[header.topAnchor constraintEqualToAnchor:sheet.topAnchor constant:24],
[header.leadingAnchor constraintEqualToAnchor:sheet.leadingAnchor constant:20],
[header.trailingAnchor constraintEqualToAnchor:sheet.trailingAnchor constant:-20],
[title.leadingAnchor constraintEqualToAnchor:header.leadingAnchor],
[title.centerYAnchor constraintEqualToAnchor:header.centerYAnchor],
// [closeButton.trailingAnchor constraintEqualToAnchor:header.trailingAnchor],
// [closeButton.centerYAnchor constraintEqualToAnchor:header.centerYAnchor],
// [closeButton.heightAnchor constraintEqualToConstant:24],
// [closeButton.widthAnchor constraintEqualToConstant:24],
[subtitle.topAnchor constraintEqualToAnchor:title.bottomAnchor constant:12],
[subtitle.leadingAnchor constraintEqualToAnchor:sheet.leadingAnchor constant:20],
[subtitle.trailingAnchor constraintEqualToAnchor:sheet.trailingAnchor constant:-20],
[bm.topAnchor constraintEqualToAnchor:subtitle.bottomAnchor constant:24],
[bm.leadingAnchor constraintEqualToAnchor:sheet.leadingAnchor],
[bm.trailingAnchor constraintEqualToAnchor:sheet.trailingAnchor],
[bm.heightAnchor constraintEqualToConstant:56],
[sep1.topAnchor constraintEqualToAnchor:bm.bottomAnchor],
[sep1.leadingAnchor constraintEqualToAnchor:sheet.leadingAnchor constant:20],
[sep1.trailingAnchor constraintEqualToAnchor:sheet.trailingAnchor constant:-20],
[sep1.heightAnchor constraintEqualToConstant:1],
[en.topAnchor constraintEqualToAnchor:sep1.bottomAnchor],
[en.leadingAnchor constraintEqualToAnchor:sheet.leadingAnchor],
[en.trailingAnchor constraintEqualToAnchor:sheet.trailingAnchor],
[en.heightAnchor constraintEqualToConstant:56],
[sep2.topAnchor constraintEqualToAnchor:en.bottomAnchor],
[sep2.leadingAnchor constraintEqualToAnchor:sheet.leadingAnchor constant:20],
[sep2.trailingAnchor constraintEqualToAnchor:sheet.trailingAnchor constant:-20],
[sep2.heightAnchor constraintEqualToConstant:1],
[zh.topAnchor constraintEqualToAnchor:sep2.bottomAnchor],
[zh.leadingAnchor constraintEqualToAnchor:sheet.leadingAnchor],
[zh.trailingAnchor constraintEqualToAnchor:sheet.trailingAnchor],
[zh.heightAnchor constraintEqualToConstant:56],
[okButton.topAnchor constraintEqualToAnchor:zh.bottomAnchor constant:32],
[okButton.leadingAnchor constraintEqualToAnchor:sheet.leadingAnchor constant:20],
[okButton.trailingAnchor constraintEqualToAnchor:sheet.trailingAnchor constant:-20],
[okButton.heightAnchor constraintEqualToConstant:52],
[okButton.bottomAnchor constraintEqualToAnchor:sheet.safeAreaLayoutGuide.bottomAnchor constant:-16],
]];
return sheet;
}
- (UIControl *)languageRow:(NSString *)title selected:(BOOL)selected tag:(NSInteger)tag {
UIControl *row = [[UIControl alloc] init];
row.tag = tag;
row.translatesAutoresizingMaskIntoConstraints = NO;
[row addTarget:self action:@selector(languageTapped:) forControlEvents:UIControlEventTouchUpInside];
UILabel *label = [[UILabel alloc] init];
label.text = title;
label.font = [UIFont systemFontOfSize:18 weight:UIFontWeightSemibold];
label.translatesAutoresizingMaskIntoConstraints = NO;
UIView *radioOuter = [[UIView alloc] init];
radioOuter.layer.cornerRadius = 12;
radioOuter.layer.borderWidth = 2;
radioOuter.layer.borderColor = UIColor.systemGray4Color.CGColor;
radioOuter.translatesAutoresizingMaskIntoConstraints = NO;
UIView *radioInner = [[UIView alloc] init];
radioInner.layer.cornerRadius = 6;
radioInner.backgroundColor = selected
? [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0]
: UIColor.clearColor;
radioInner.translatesAutoresizingMaskIntoConstraints = NO;
[radioOuter addSubview:radioInner];
[row addSubview:label];
[row addSubview:radioOuter];
[NSLayoutConstraint activateConstraints:@[
[label.leadingAnchor constraintEqualToAnchor:row.leadingAnchor constant:20],
[label.centerYAnchor constraintEqualToAnchor:row.centerYAnchor],
[radioOuter.trailingAnchor constraintEqualToAnchor:row.trailingAnchor constant:-20],
[radioOuter.centerYAnchor constraintEqualToAnchor:row.centerYAnchor],
[radioOuter.widthAnchor constraintEqualToConstant:24],
[radioOuter.heightAnchor constraintEqualToConstant:24],
[radioInner.centerXAnchor constraintEqualToAnchor:radioOuter.centerXAnchor],
[radioInner.centerYAnchor constraintEqualToAnchor:radioOuter.centerYAnchor],
[radioInner.widthAnchor constraintEqualToConstant:12],
[radioInner.heightAnchor constraintEqualToConstant:12],
]];
return row;
}
- (void)confirmLanguage {
// 1. Make sure user selected something
if (self.selectedLanguage == NSNotFound) {
UIAlertController *alert =
[UIAlertController alertControllerWithTitle:nil
message:@"Please select a language"
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *ok =
[UIAlertAction actionWithTitle:@"OK"
style:UIAlertActionStyleDefault
handler:nil];
[alert addAction:ok];
[self presentViewController:alert animated:YES completion:nil];
return;
}
// 2. Convert to language code
NSString *languageCode = @"en";
switch (self.selectedLanguage) {
case AppLanguageEnglish:
languageCode = @"en";
break;
case AppLanguageMalay:
languageCode = @"ms";
break;
case AppLanguageChinese:
languageCode = @"zh";
break;
}
// 3. Save language
[[NSUserDefaults standardUserDefaults] setObject:languageCode forKey:@"AppLanguage"];
[[NSUserDefaults standardUserDefaults] synchronize];
// 4. Apply language change
// [LanguageManager setLanguage:languageCode];
// 5. Notify app to refresh UI
[[NSNotificationCenter defaultCenter]
postNotificationName:@"LanguageDidChangeNotification"
object:nil];
// 6. Close popup
[self dismissAddLinkSheet:^{NSLog(@"link sheet dismissed");}];
}
- (void)changeLanguageTapped {
[self.addLinkSheet removeFromSuperview];
[self.dimmedOverlay removeFromSuperview];
self.dimmedOverlay = [self buildDimmedOverlay];
self.addLinkSheet = [self buildLanguageSheet]; // reuse property for now
[self.view addSubview:self.dimmedOverlay];
[self.view addSubview:self.addLinkSheet];
NSLayoutConstraint *bottom = [self.addLinkSheet.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor constant:300];
bottom.active = YES;
[NSLayoutConstraint activateConstraints:@[
[self.addLinkSheet.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.addLinkSheet.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
]];
[self.view layoutIfNeeded];
[UIView animateWithDuration:0.3 animations:^{
self.dimmedOverlay.alpha = 1;
bottom.constant = 0;
[self.view layoutIfNeeded];
}];
}
- (void)languageTapped:(UIControl *)sender {
self.selectedLanguageIndex = sender.tag;
for (UIControl *row in self.languageRows) {
UIView *radioOuter = row.subviews.lastObject;
UIView *radioInner = radioOuter.subviews.firstObject;
radioInner.backgroundColor =
(row.tag == self.selectedLanguageIndex)
? [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0]
: UIColor.clearColor;
}
}
-(void)updateTapped{
NSLog(@"update tapped");
[APIClient editProfile:self.linkNameField.text completion:^(BOOL success, NSDictionary * _Nullable data, NSError * _Nullable error) {
......@@ -786,8 +1052,9 @@
if (!error) {
NSLog(@"Successfully edited profile name");
[self dismissAddLinkSheet];
[self dismissAddLinkSheet:^{
[self requestProfile];
}];
}
}];
}
......@@ -861,14 +1128,6 @@ didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *
[picker dismissViewControllerAnimated:YES completion:nil];
}
- (void) changeLanguageTapped {
NSLog(@"Change Language Tapped");
}
-(void) switchAccountTapped{
NSLog(@"Switch Account Tapped");
}
- (void)profileImageTapped {
if (!self.profileImageView.image) return;
......@@ -936,4 +1195,520 @@ didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *
}];
}
#pragma mark - Switch Account
-(void) switchAccountTapped{
[self.addLinkSheet removeFromSuperview];
[self.dimmedOverlay removeFromSuperview];
self.dimmedOverlay = [self buildDimmedOverlay];
self.addLinkSheet = [self buildAccountSheet];
self.accounts = @[
@{
@"name": @"Jason Snow",
@"company_code": @"SPSetia",
@"userName": @"jasonSnow6602",
@"loggedIn": @NO
},
@{
@"name": @"John Anthony Snow",
@"company_code": @"QMSI",
@"userName": @"JohnSnow132",
@"loggedIn": @YES
},
@{
@"name": @"Kenny Soo",
@"company_code": @"QMSI",
@"userName": @"kennys01",
@"loggedIn": @NO
}
];
[self.view addSubview:self.dimmedOverlay];
[self.view addSubview:self.addLinkSheet];
NSLayoutConstraint *bottom = [self.addLinkSheet.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor constant:300];
bottom.active = YES;
[NSLayoutConstraint activateConstraints:@[
[self.addLinkSheet.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.addLinkSheet.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.addLinkSheet.heightAnchor constraintEqualToConstant:423],
]];
[self.view layoutIfNeeded];
[UIView animateWithDuration:0.3 animations:^{
self.dimmedOverlay.alpha = 1;
bottom.constant = 0;
[self.view layoutIfNeeded];
}];
}
- (UIView *)buildAccountSheet {
UIView *sheet = [[UIView alloc] init];
sheet.backgroundColor = UIColor.whiteColor;
sheet.layer.cornerRadius = 24;
sheet.layer.maskedCorners = kCALayerMinXMinYCorner | kCALayerMaxXMinYCorner;
sheet.translatesAutoresizingMaskIntoConstraints = NO;
UIView *header = [[UIView alloc] init];
header.translatesAutoresizingMaskIntoConstraints = NO;
[sheet addSubview:header];
UILabel *title = [[UILabel alloc] init];
title.text = @"Switch Account";
title.font = [UIFont systemFontOfSize:20 weight:UIFontWeightBold];
title.translatesAutoresizingMaskIntoConstraints = NO;
// UIButton *closeButton = [UIButton buttonWithType:UIButtonTypeSystem];
// [closeButton setImage:[UIImage systemImageNamed:@"xmark"] forState:UIControlStateNormal];
// closeButton.tintColor = UIColor.systemGrayColor;
// [closeButton addTarget:self action:@selector(dismissAddLinkSheetButtonTapped:)
// forControlEvents:UIControlEventTouchUpInside];
// closeButton.translatesAutoresizingMaskIntoConstraints = NO;
[header addSubview:title];
// [header addSubview:closeButton];
UILabel *subtitle = [[UILabel alloc] init];
subtitle.text = @"Select an account you want to switch to.";
subtitle.font = [UIFont systemFontOfSize:14];
subtitle.textAlignment = NSTextAlignmentLeft;
subtitle.numberOfLines = 0;
subtitle.textColor = UIColor.darkGrayColor;
subtitle.translatesAutoresizingMaskIntoConstraints = NO;
[sheet addSubview:subtitle];
// --- Account Table ---
self.accountTable = [[UITableView alloc] init];
self.accountTable.translatesAutoresizingMaskIntoConstraints = NO;
self.accountTable.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
self.accountTable.delegate = self;
self.accountTable.dataSource = self;
self.accountTable.rowHeight = 72;
self.accountTable.tableFooterView = [UIView new];
self.accountTable.alwaysBounceVertical = YES;
[sheet addSubview:self.accountTable];
//Ok Button
UIButton *manageButton = [UIButton buttonWithType:UIButtonTypeSystem];
[manageButton setTitle:@"Manage Accounts" forState:UIControlStateNormal];
manageButton.titleLabel.font = [UIFont systemFontOfSize:14];
manageButton.backgroundColor = [UIColor whiteColor];
manageButton.layer.cornerRadius = 18;
manageButton.layer.borderWidth = 0.5;
manageButton.layer.borderColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0].CGColor;
[manageButton setTitleColor:[UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0] forState:UIControlStateNormal];
[manageButton addTarget:self action:@selector(manageAccountsTapped)
forControlEvents:UIControlEventTouchUpInside];
manageButton.translatesAutoresizingMaskIntoConstraints = NO;
[sheet addSubview:manageButton];
UIButton *accountButton = [UIButton buttonWithType:UIButtonTypeSystem];
[accountButton setTitle:@"Add Account" forState:UIControlStateNormal];
accountButton.titleLabel.font = [UIFont systemFontOfSize:14];
accountButton.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0];
accountButton.layer.cornerRadius = 18;
[accountButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
[accountButton addTarget:self action:@selector(addAccountsTapped)
forControlEvents:UIControlEventTouchUpInside];
accountButton.translatesAutoresizingMaskIntoConstraints = NO;
[sheet addSubview:accountButton];
[NSLayoutConstraint activateConstraints:@[
[header.topAnchor constraintEqualToAnchor:sheet.topAnchor constant:24],
[header.leadingAnchor constraintEqualToAnchor:sheet.leadingAnchor constant:20],
[header.trailingAnchor constraintEqualToAnchor:sheet.trailingAnchor constant:-20],
[title.leadingAnchor constraintEqualToAnchor:header.leadingAnchor],
[title.centerYAnchor constraintEqualToAnchor:header.centerYAnchor],
// [closeButton.trailingAnchor constraintEqualToAnchor:header.trailingAnchor],
// [closeButton.centerYAnchor constraintEqualToAnchor:header.centerYAnchor],
// [closeButton.heightAnchor constraintEqualToConstant:24],
// [closeButton.widthAnchor constraintEqualToConstant:24],
[subtitle.topAnchor constraintEqualToAnchor:title.bottomAnchor constant:12],
[subtitle.leadingAnchor constraintEqualToAnchor:sheet.leadingAnchor constant:20],
[subtitle.trailingAnchor constraintEqualToAnchor:sheet.trailingAnchor constant:-20],
[self.accountTable.topAnchor constraintEqualToAnchor:subtitle.bottomAnchor constant:16],
[self.accountTable.leadingAnchor constraintEqualToAnchor:sheet.leadingAnchor],
[self.accountTable.trailingAnchor constraintEqualToAnchor:sheet.trailingAnchor],
[self.accountTable.bottomAnchor constraintEqualToAnchor:manageButton.topAnchor constant:-24],
[manageButton.topAnchor constraintEqualToAnchor:self.accountTable.bottomAnchor constant:32],
[manageButton.leadingAnchor constraintEqualToAnchor:sheet.leadingAnchor constant:16],
[manageButton.trailingAnchor constraintEqualToAnchor:sheet.centerXAnchor constant:-8],
[manageButton.heightAnchor constraintEqualToConstant:48],
[manageButton.bottomAnchor constraintEqualToAnchor:sheet.safeAreaLayoutGuide.bottomAnchor constant:-16],
[accountButton.topAnchor constraintEqualToAnchor:manageButton.topAnchor],
[accountButton.leadingAnchor constraintEqualToAnchor:sheet.centerXAnchor constant:8],
[accountButton.trailingAnchor constraintEqualToAnchor:sheet.trailingAnchor constant:-16],
[accountButton.heightAnchor constraintEqualToConstant:48],
[accountButton.bottomAnchor constraintEqualToAnchor:manageButton.bottomAnchor]
]];
return sheet;
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
return self.accounts.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellId = @"AccountCell";
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:cellId];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:cellId];
// --- Profile Image Placeholder ---
UIImageView *profileImageView = [[UIImageView alloc] init];
profileImageView.tag = 1000;
profileImageView.translatesAutoresizingMaskIntoConstraints = NO;
profileImageView.backgroundColor = UIColor.systemGray4Color;
profileImageView.layer.cornerRadius = 20; // half of width/height
profileImageView.clipsToBounds = YES;
[cell.contentView addSubview:profileImageView];
// Name label
UILabel *nameLabel = [[UILabel alloc] init];
nameLabel.tag = 1001;
nameLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightSemibold];
nameLabel.translatesAutoresizingMaskIntoConstraints = NO;
// Company code
UILabel *companyLabel = [[UILabel alloc] init];
companyLabel.tag = 1002;
companyLabel.font = [UIFont systemFontOfSize:13];
companyLabel.textColor = UIColor.systemGrayColor;
companyLabel.translatesAutoresizingMaskIntoConstraints = NO;
// Dot
UILabel *dotLabel = [[UILabel alloc] init];
dotLabel.text = @"·";
dotLabel.tag = 1003;
dotLabel.font = [UIFont systemFontOfSize:13];
dotLabel.textColor = UIColor.systemGray3Color;
dotLabel.translatesAutoresizingMaskIntoConstraints = NO;
// Username
UILabel *userLabel = [[UILabel alloc] init];
userLabel.tag = 1004;
userLabel.font = [UIFont systemFontOfSize:13];
userLabel.textColor = UIColor.systemGrayColor;
userLabel.translatesAutoresizingMaskIntoConstraints = NO;
[cell.contentView addSubview:nameLabel];
[cell.contentView addSubview:companyLabel];
[cell.contentView addSubview:dotLabel];
[cell.contentView addSubview:userLabel];
// Constraints
[NSLayoutConstraint activateConstraints:@[
// Profile image
[profileImageView.leadingAnchor constraintEqualToAnchor:cell.contentView.leadingAnchor constant:16],
[profileImageView.centerYAnchor constraintEqualToAnchor:cell.contentView.centerYAnchor],
[profileImageView.widthAnchor constraintEqualToConstant:40],
[profileImageView.heightAnchor constraintEqualToConstant:40],
// Name label
[nameLabel.topAnchor constraintEqualToAnchor:cell.contentView.topAnchor constant:12],
[nameLabel.leadingAnchor constraintEqualToAnchor:profileImageView.trailingAnchor constant:12],
[nameLabel.trailingAnchor constraintLessThanOrEqualToAnchor:cell.contentView.trailingAnchor constant:-16],
// Company label
[companyLabel.topAnchor constraintEqualToAnchor:nameLabel.bottomAnchor constant:4],
[companyLabel.leadingAnchor constraintEqualToAnchor:nameLabel.leadingAnchor],
// Dot
[dotLabel.centerYAnchor constraintEqualToAnchor:companyLabel.centerYAnchor],
[dotLabel.leadingAnchor constraintEqualToAnchor:companyLabel.trailingAnchor constant:6],
// Username
[userLabel.centerYAnchor constraintEqualToAnchor:companyLabel.centerYAnchor],
[userLabel.leadingAnchor constraintEqualToAnchor:dotLabel.trailingAnchor constant:6],
[userLabel.trailingAnchor constraintLessThanOrEqualToAnchor:cell.contentView.trailingAnchor constant:-16],
]];
}
NSDictionary *account = self.accounts[indexPath.row];
UILabel *nameLabel = [cell.contentView viewWithTag:1001];
UILabel *companyLabel = [cell.contentView viewWithTag:1002];
UILabel *userLabel = [cell.contentView viewWithTag:1004];
nameLabel.text = account[@"name"];
companyLabel.text = account[@"company_code"];
userLabel.text = account[@"userName"];
// Right-side status
BOOL loggedIn = [account[@"loggedIn"] boolValue];
cell.accessoryView = nil;
if (loggedIn) {
UILabel *pill = [[UILabel alloc] initWithFrame:CGRectMake(0,0,88,28)];
pill.text = @"Logged In";
pill.font = [UIFont systemFontOfSize:12 weight:UIFontWeightSemibold];
pill.textAlignment = NSTextAlignmentCenter;
pill.backgroundColor = UIColor.systemGreenColor;
pill.textColor = UIColor.whiteColor;
pill.layer.cornerRadius = 14;
pill.clipsToBounds = YES;
cell.accessoryView = pill;
} else {
UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem];
[btn setTitle:@"Switch" forState:UIControlStateNormal];
btn.titleLabel.font = [UIFont systemFontOfSize:13 weight:UIFontWeightSemibold];
btn.layer.borderWidth = 1;
btn.layer.borderColor = UIColor.systemGray4Color.CGColor;
btn.layer.cornerRadius = 14;
btn.frame = CGRectMake(0,0,88,28);
cell.accessoryView = btn;
[btn addTarget:self action:@selector(switchTapped:)
forControlEvents:UIControlEventTouchUpInside];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
-(void)manageAccountsTapped {
NSLog(@"Manage Accounts Tapped");
[self dismissAddLinkSheet:^{
ManageAccountViewController *vc = [[ManageAccountViewController alloc] init];
vc.accounts = self.accounts;
vc.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:vc animated:YES completion:nil];
}];
}
-(void)switchTapped:(UIButton *)sender {
// 1. Find the cell that contains this button
UITableViewCell *cell = (UITableViewCell *)sender.superview;
while (cell && ![cell isKindOfClass:[UITableViewCell class]]) {
cell = (UITableViewCell *)cell.superview;
}
if (!cell) return;
NSIndexPath *indexPath = [self.accountTable indexPathForCell:cell];
if (!indexPath) return;
// 2. Update self.accounts
NSMutableArray *updatedAccounts = [self.accounts mutableCopy];
// Set all loggedIn = NO first
for (NSInteger i = 0; i < updatedAccounts.count; i++) {
NSMutableDictionary *acct = [updatedAccounts[i] mutableCopy];
acct[@"loggedIn"] = @NO;
updatedAccounts[i] = acct;
}
// Set the selected account to loggedIn = YES
NSMutableDictionary *selectedAccount = [updatedAccounts[indexPath.row] mutableCopy];
selectedAccount[@"loggedIn"] = @YES;
updatedAccounts[indexPath.row] = selectedAccount;
self.accounts = [updatedAccounts copy];
// 3. Reload the table
[self.accountTable reloadData];
}
-(void)addAccountsTapped{
NSLog(@"Add Accounts Tapped");
[self dismissAddLinkSheet:^{
// now fully dismissed, safe to show new sheet
self.dimmedOverlay = [self buildDimmedOverlay];
self.addLinkSheet = [self addAccountSheet];
[self.view addSubview:self.dimmedOverlay];
[self.view addSubview:self.addLinkSheet];
NSLayoutConstraint *bottom = [self.addLinkSheet.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor constant:300];
bottom.active = YES;
[NSLayoutConstraint activateConstraints:@[
[self.addLinkSheet.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.addLinkSheet.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.addLinkSheet.heightAnchor constraintEqualToConstant:250],
]];
[self.view layoutIfNeeded];
[UIView animateWithDuration:0.3 animations:^{
self.dimmedOverlay.alpha = 1;
bottom.constant = 0;
[self.view layoutIfNeeded];
}];
}];
}
- (UIView *)addAccountSheet {
UIView *sheet = [[UIView alloc] init];
sheet.backgroundColor = UIColor.whiteColor;
sheet.layer.cornerRadius = 24;
sheet.layer.maskedCorners = kCALayerMinXMinYCorner | kCALayerMaxXMinYCorner;
sheet.translatesAutoresizingMaskIntoConstraints = NO;
UIView *header = [[UIView alloc] init];
header.translatesAutoresizingMaskIntoConstraints = NO;
[sheet addSubview:header];
UILabel *title = [[UILabel alloc] init];
title.text = @"Add Account";
title.font = [UIFont systemFontOfSize:18 weight:UIFontWeightBold];
title.translatesAutoresizingMaskIntoConstraints = NO;
// UIButton *closeButton = [UIButton buttonWithType:UIButtonTypeSystem];
// [closeButton setImage:[UIImage systemImageNamed:@"xmark"] forState:UIControlStateNormal];
// closeButton.tintColor = UIColor.systemGrayColor;
// [closeButton addTarget:self action:@selector(dismissAddLinkSheetButtonTapped:)
// forControlEvents:UIControlEventTouchUpInside];
// closeButton.translatesAutoresizingMaskIntoConstraints = NO;
[header addSubview:title];
// [header addSubview:closeButton];
UILabel *subtitle = [[UILabel alloc] init];
subtitle.text = @"Select an option to proceed.";
subtitle.font = [UIFont systemFontOfSize:14];
subtitle.textAlignment = NSTextAlignmentLeft;
subtitle.numberOfLines = 0;
subtitle.textColor = UIColor.darkGrayColor;
subtitle.translatesAutoresizingMaskIntoConstraints = NO;
[sheet addSubview:subtitle];
UIView *spacer1 = [[UIView alloc] init];
spacer1.translatesAutoresizingMaskIntoConstraints = NO;
spacer1.layer.borderWidth = 0.5;
spacer1.layer.borderColor = [UIColor lightGrayColor].CGColor;
[sheet addSubview:spacer1];
// --- Existing Account ---
UIView *existingAccount = [[UIView alloc] init];
existingAccount.translatesAutoresizingMaskIntoConstraints = NO;
[sheet addSubview:existingAccount];
UILabel *existingTitle = [[UILabel alloc] init];
existingTitle.text = @"Add Existing Account";
existingTitle.font = [UIFont systemFontOfSize:16 weight:UIFontWeightBold];
existingTitle.translatesAutoresizingMaskIntoConstraints = NO;
UIButton *existingButton = [UIButton buttonWithType:UIButtonTypeSystem];
[existingButton setImage:[UIImage systemImageNamed:@"plus"] forState:UIControlStateNormal];
existingButton.tintColor = UIColor.systemGrayColor;
[existingButton addTarget:self action:@selector(existingButtonTapped)
forControlEvents:UIControlEventTouchUpInside];
existingButton.translatesAutoresizingMaskIntoConstraints = NO;
[existingAccount addSubview:existingTitle];
[existingAccount addSubview:existingButton];
UIView *spacer2 = [[UIView alloc] init];
spacer2.translatesAutoresizingMaskIntoConstraints = NO;
spacer2.layer.borderWidth = 0.5;
spacer2.layer.borderColor = [UIColor lightGrayColor].CGColor;
[sheet addSubview:spacer2];
// --- New Account ---
UIView *newAccount = [[UIView alloc] init];
newAccount.translatesAutoresizingMaskIntoConstraints = NO;
[sheet addSubview:newAccount];
UILabel *newTitle = [[UILabel alloc] init];
newTitle.text = @"Add New Account";
newTitle.font = [UIFont systemFontOfSize:16 weight:UIFontWeightBold];
newTitle.translatesAutoresizingMaskIntoConstraints = NO;
UIButton *newButton = [UIButton buttonWithType:UIButtonTypeSystem];
[newButton setImage:[UIImage systemImageNamed:@"plus"] forState:UIControlStateNormal];
newButton.tintColor = UIColor.systemGrayColor;
[newButton addTarget:self action:@selector(newButtonTapped)
forControlEvents:UIControlEventTouchUpInside];
newButton.translatesAutoresizingMaskIntoConstraints = NO;
[newAccount addSubview:newTitle];
[newAccount addSubview:newButton];
[NSLayoutConstraint activateConstraints:@[
[header.topAnchor constraintEqualToAnchor:sheet.topAnchor constant:24],
[header.leadingAnchor constraintEqualToAnchor:sheet.leadingAnchor constant:20],
[header.trailingAnchor constraintEqualToAnchor:sheet.trailingAnchor constant:-20],
[title.leadingAnchor constraintEqualToAnchor:header.leadingAnchor],
[title.topAnchor constraintEqualToAnchor:header.topAnchor],
// [closeButton.trailingAnchor constraintEqualToAnchor:header.trailingAnchor],
// [closeButton.centerYAnchor constraintEqualToAnchor:title.centerYAnchor],
// [closeButton.heightAnchor constraintEqualToConstant:24],
// [closeButton.widthAnchor constraintEqualToConstant:24],
[subtitle.topAnchor constraintEqualToAnchor:title.bottomAnchor constant:12],
[subtitle.leadingAnchor constraintEqualToAnchor:sheet.leadingAnchor constant:20],
[subtitle.trailingAnchor constraintEqualToAnchor:sheet.trailingAnchor constant:-20],
[spacer1.topAnchor constraintEqualToAnchor:subtitle.bottomAnchor constant:20],
[spacer1.leadingAnchor constraintEqualToAnchor:sheet.leadingAnchor],
[spacer1.trailingAnchor constraintEqualToAnchor:sheet.trailingAnchor],
[spacer1.heightAnchor constraintEqualToConstant:1],
[existingAccount.topAnchor constraintEqualToAnchor:spacer1.bottomAnchor constant:20],
[existingAccount.leadingAnchor constraintEqualToAnchor:sheet.leadingAnchor constant:16],
[existingAccount.trailingAnchor constraintEqualToAnchor:sheet.trailingAnchor constant:-16],
[existingTitle.topAnchor constraintEqualToAnchor:existingAccount.topAnchor],
[existingTitle.leadingAnchor constraintEqualToAnchor:existingAccount.leadingAnchor],
[existingTitle.trailingAnchor constraintEqualToAnchor:existingButton.leadingAnchor constant:-16],
[existingButton.centerYAnchor constraintEqualToAnchor:existingTitle.centerYAnchor],
[existingButton.trailingAnchor constraintEqualToAnchor:existingAccount.trailingAnchor],
[existingButton.heightAnchor constraintEqualToConstant:24],
[existingButton.widthAnchor constraintEqualToConstant:24],
[spacer2.topAnchor constraintEqualToAnchor:existingButton.bottomAnchor constant:18],
[spacer2.leadingAnchor constraintEqualToAnchor:sheet.leadingAnchor constant:16],
[spacer2.trailingAnchor constraintEqualToAnchor:sheet.trailingAnchor constant:-16],
[spacer2.heightAnchor constraintEqualToConstant:1],
[newAccount.topAnchor constraintEqualToAnchor:spacer2.bottomAnchor constant:18],
[newAccount.leadingAnchor constraintEqualToAnchor:sheet.leadingAnchor constant:16],
[newAccount.trailingAnchor constraintEqualToAnchor:sheet.trailingAnchor constant:-16],
[newTitle.topAnchor constraintEqualToAnchor:newAccount.topAnchor],
[newTitle.leadingAnchor constraintEqualToAnchor:newAccount.leadingAnchor],
[newTitle.trailingAnchor constraintEqualToAnchor:newButton.leadingAnchor constant:-16],
[newButton.centerYAnchor constraintEqualToAnchor:newTitle.centerYAnchor],
[newButton.trailingAnchor constraintEqualToAnchor:newAccount.trailingAnchor],
[newButton.heightAnchor constraintEqualToConstant:24],
[newButton.widthAnchor constraintEqualToConstant:24],
]];
return sheet;
}
-(void)existingButtonTapped{
NSLog(@"existing account button tapped");
}
-(void)newButtonTapped {
NSLog(@"new account button tapped");
}
#pragma mark - Helpers
- (void)onBack {
[self dismissViewControllerAnimated:YES completion:nil];
}
@end
......@@ -797,14 +797,14 @@ static NSString * const kSyncSelectedUnitsKey = @"SYNC_SELECTEDUNITS";
} next:next];
}];
// Task 9 — requestAnnouncement
// Task 9 — requestClientAnnouncement
[tasks addObject:^(void (^next)(void)) {
[self safeSequentialTask:@"task9" block:^(void (^safeNext)(void), void (^logSuccess)(BOOL)) {
NSLog(@"🚀 Starting Task 9");
[APIClient requestAnnouncement:^(BOOL success, NSDictionary *res, NSError *err) {
[APIClient requestClientAnnouncement:^(BOOL success, NSDictionary *res, NSError *err) {
NSString *logText = [NSString stringWithFormat:
@"\n🚀 Task 9 — requestAnnouncement\nTime: %@\nError: %@\nResponse: %@\n",
@"\n🚀 Task 9 — requestClientAnnouncement\nTime: %@\nError: %@\nResponse: %@\n",
[NSDate date], err, res];
[self appendOfflineLog:logText];
......
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