Commit 1eec3cd3 authored by Wei Han's avatar Wei Han

code update

parent 61a8bfd5
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<dict> <dict>
<key>Assets.car</key> <key>Assets.car</key>
<data> <data>
KnMHH8GU4NZESWbs6/0uU5WX8uA= EqtjfGVJUrKupCnFW6lfffSo2ZA=
</data> </data>
<key>Headers/QmsPlugin.h</key> <key>Headers/QmsPlugin.h</key>
<data> <data>
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
</data> </data>
<key>Info.plist</key> <key>Info.plist</key>
<data> <data>
ScoY0XAgmZ3U9Q0BvlfgQfJm2bo= w8N5kkR8hr/wIwb/x0XA5+wVpdo=
</data> </data>
<key>Modules/module.modulemap</key> <key>Modules/module.modulemap</key>
<data> <data>
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
<dict> <dict>
<key>hash2</key> <key>hash2</key>
<data> <data>
aLAhYopvL1Lb4CTMG5A8x8RAmnkpXwHQbjsJdpq8gYg= k78SvGog/XWiM8sEWRQ8ZyFHnocCgVMjS4SisBwChjI=
</data> </data>
</dict> </dict>
<key>Headers/QmsPlugin.h</key> <key>Headers/QmsPlugin.h</key>
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<dict> <dict>
<key>Assets.car</key> <key>Assets.car</key>
<data> <data>
KnMHH8GU4NZESWbs6/0uU5WX8uA= EqtjfGVJUrKupCnFW6lfffSo2ZA=
</data> </data>
<key>Headers/QmsPlugin.h</key> <key>Headers/QmsPlugin.h</key>
<data> <data>
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
</data> </data>
<key>Info.plist</key> <key>Info.plist</key>
<data> <data>
JGviPenfphujtQEGyJZCIZTsd2c= uEkE+l7bQzwu7vnX83uBlOCEpCk=
</data> </data>
<key>Modules/module.modulemap</key> <key>Modules/module.modulemap</key>
<data> <data>
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
<dict> <dict>
<key>hash2</key> <key>hash2</key>
<data> <data>
aLAhYopvL1Lb4CTMG5A8x8RAmnkpXwHQbjsJdpq8gYg= k78SvGog/XWiM8sEWRQ8ZyFHnocCgVMjS4SisBwChjI=
</data> </data>
</dict> </dict>
<key>Headers/QmsPlugin.h</key> <key>Headers/QmsPlugin.h</key>
......
...@@ -20,7 +20,26 @@ ...@@ -20,7 +20,26 @@
- (void)viewDidLoad { - (void)viewDidLoad {
[super viewDidLoad]; [super viewDidLoad];
self.view.backgroundColor = [UIColor systemGroupedBackgroundColor];
// --- Base background (replaces systemGroupedBackground) ---
self.view.backgroundColor = [UIColor whiteColor];
// --- Header bar color ---
self.headerView.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0]; // teal
self.titleLabel.textColor = [UIColor whiteColor];
// --- TableView styling ---
self.tableView.backgroundColor = [UIColor colorWithWhite:0.97 alpha:1.0]; // very light gray
self.tableView.separatorColor = [UIColor colorWithWhite:0.9 alpha:1.0];
// --- Section header label colors ---
self.tableView.sectionIndexColor = [UIColor darkGrayColor];
// --- Optional: consistent scroll indicator style ---
self.tableView.indicatorStyle = UIScrollViewIndicatorStyleBlack;
// --- Tint / global accent color (used for buttons, etc) ---
self.view.tintColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0];
[self setupHeader]; [self setupHeader];
[self setupTableView]; [self setupTableView];
...@@ -36,7 +55,8 @@ ...@@ -36,7 +55,8 @@
#pragma mark - Header #pragma mark - Header
- (void)setupHeader { - (void)setupHeader {
self.headerView = [[UIView alloc] init]; CGFloat statusBarHeight = UIApplication.sharedApplication.statusBarFrame.size.height;
self.headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, statusBarHeight + 60)];
self.headerView.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0]; self.headerView.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0];
self.headerView.translatesAutoresizingMaskIntoConstraints = NO; self.headerView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.headerView]; [self.view addSubview:self.headerView];
...@@ -56,13 +76,6 @@ ...@@ -56,13 +76,6 @@
self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO; self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
[self.headerView addSubview:self.titleLabel]; [self.headerView addSubview:self.titleLabel];
self.addInfoButton = [UIButton buttonWithType:UIButtonTypeSystem];
[self.addInfoButton setImage:[UIImage systemImageNamed:@"plus"] forState:UIControlStateNormal];
self.addInfoButton.tintColor = UIColor.whiteColor;
self.addInfoButton.translatesAutoresizingMaskIntoConstraints = NO;
[self.addInfoButton addTarget:self action:@selector(addInfoTapped) forControlEvents:UIControlEventTouchUpInside];
[self.headerView addSubview:self.addInfoButton];
[NSLayoutConstraint activateConstraints:@[ [NSLayoutConstraint activateConstraints:@[
[self.headerView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor], [self.headerView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor],
[self.headerView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], [self.headerView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
...@@ -72,9 +85,6 @@ ...@@ -72,9 +85,6 @@
[self.backButton.leadingAnchor constraintEqualToAnchor:self.headerView.leadingAnchor constant:12], [self.backButton.leadingAnchor constraintEqualToAnchor:self.headerView.leadingAnchor constant:12],
[self.backButton.centerYAnchor constraintEqualToAnchor:self.headerView.centerYAnchor], [self.backButton.centerYAnchor constraintEqualToAnchor:self.headerView.centerYAnchor],
[self.addInfoButton.trailingAnchor constraintEqualToAnchor:self.headerView.trailingAnchor constant:-12],
[self.addInfoButton.centerYAnchor constraintEqualToAnchor:self.headerView.centerYAnchor],
[self.titleLabel.centerXAnchor constraintEqualToAnchor:self.headerView.centerXAnchor], [self.titleLabel.centerXAnchor constraintEqualToAnchor:self.headerView.centerXAnchor],
[self.titleLabel.centerYAnchor constraintEqualToAnchor:self.headerView.centerYAnchor], [self.titleLabel.centerYAnchor constraintEqualToAnchor:self.headerView.centerYAnchor],
]]; ]];
...@@ -87,6 +97,9 @@ ...@@ -87,6 +97,9 @@
self.tableView.delegate = self; self.tableView.delegate = self;
self.tableView.dataSource = self; self.tableView.dataSource = self;
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
self.tableView.backgroundView = nil;
self.tableView.backgroundColor = [UIColor whiteColor];
self.tableView.opaque = YES;
[self.view addSubview:self.tableView]; [self.view addSubview:self.tableView];
[NSLayoutConstraint activateConstraints:@[ [NSLayoutConstraint activateConstraints:@[
...@@ -186,6 +199,9 @@ ...@@ -186,6 +199,9 @@
if (!cell) { if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]; cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
cell.selectionStyle = UITableViewCellSelectionStyleNone; cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.backgroundColor = [UIColor clearColor];
cell.contentView.backgroundColor = [UIColor clearColor];
UIView *card = [[UIView alloc] init]; UIView *card = [[UIView alloc] init];
card.tag = 100; card.tag = 100;
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
@property (nonatomic, strong) UIView *detailsCard; @property (nonatomic, strong) UIView *detailsCard;
@property (nonatomic, strong) UIButton *editButton; @property (nonatomic, strong) UIButton *editButton;
@property (nonatomic, strong) UIButton *deleteButton; @property (nonatomic, strong) UIButton *deleteButton;
@property (nonatomic, strong) UIImageView *floorPlanThumbnail;
@end @end
...@@ -150,11 +151,33 @@ ...@@ -150,11 +151,33 @@
CGFloat y = 20; CGFloat y = 20;
// --- Reference ID --- // --- Reference ID ---
self.refLabel = [[UILabel alloc] initWithFrame:CGRectMake(padding, y, self.view.bounds.size.width - 2*padding, 24)]; CGFloat thumbWidth = 40;
CGFloat gap = 12;
self.refLabel = [[UILabel alloc] initWithFrame:CGRectMake(padding, y, self.view.bounds.size.width - 2*padding - thumbWidth - gap, 24)];
self.refLabel.font = [UIFont boldSystemFontOfSize:20]; self.refLabel.font = [UIFont boldSystemFontOfSize:20];
self.refLabel.textColor = UIColor.blackColor; // make sure it’s visible
self.refLabel.numberOfLines = 1;
self.refLabel.adjustsFontSizeToFitWidth = YES;
[self.detailsCard addSubview:self.refLabel]; [self.detailsCard addSubview:self.refLabel];
y += 36; y += 36;
// --- Floor Plan Thumbnail ---
CGFloat thumbSize = 100; // new size
self.floorPlanThumbnail = [[UIImageView alloc] initWithFrame:
CGRectMake(self.view.bounds.size.width - padding - thumbSize, 20, thumbSize, thumbSize)];
self.floorPlanThumbnail.contentMode = UIViewContentModeScaleAspectFill;
self.floorPlanThumbnail.clipsToBounds = YES;
self.floorPlanThumbnail.layer.cornerRadius = 4;
self.floorPlanThumbnail.backgroundColor = [UIColor colorWithWhite:0.9 alpha:1];
self.floorPlanThumbnail.layer.borderColor = [UIColor systemGray3Color].CGColor;
self.floorPlanThumbnail.layer.borderWidth = 1.0;
self.floorPlanThumbnail.userInteractionEnabled = YES;
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleFloorPlanTap)];
[self.floorPlanThumbnail addGestureRecognizer:tap];
[self.detailsCard addSubview:self.floorPlanThumbnail];
// --- Status Capsule --- // --- Status Capsule ---
self.statusLabel = [[UILabel alloc] initWithFrame:CGRectMake(padding, y, 90, 28)]; self.statusLabel = [[UILabel alloc] initWithFrame:CGRectMake(padding, y, 90, 28)];
self.statusLabel.font = [UIFont boldSystemFontOfSize:14]; self.statusLabel.font = [UIFont boldSystemFontOfSize:14];
...@@ -341,6 +364,20 @@ ...@@ -341,6 +364,20 @@
} }
}); });
} }
NSString *planThumbURL = self.issueData[@"plan_image_thumb"];
if (planThumbURL.length > 0) {
NSURL *url = [NSURL URLWithString:planThumbURL];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *data = [NSData dataWithContentsOfURL:url];
if (data) {
UIImage *img = [UIImage imageWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
self.floorPlanThumbnail.image = img;
});
}
});
}
} }
- (void)scrollViewDidScroll:(UIScrollView *)scrollView { - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
...@@ -378,7 +415,6 @@ ...@@ -378,7 +415,6 @@
}]; }];
} }
- (void)closeFullImage { - (void)closeFullImage {
UIView *overlay = [self.view viewWithTag:900]; UIView *overlay = [self.view viewWithTag:900];
if (!overlay) return; if (!overlay) return;
...@@ -390,6 +426,53 @@ ...@@ -390,6 +426,53 @@
}]; }];
} }
- (void)handleFloorPlanTap {
NSString *planFullURL = self.issueData[@"plan_image"];
if (planFullURL.length == 0) return; // no full image available
UIView *overlay = [[UIView alloc] initWithFrame:self.view.bounds];
overlay.backgroundColor = [UIColor colorWithWhite:0 alpha:0.95];
overlay.alpha = 0;
overlay.tag = 901;
overlay.userInteractionEnabled = YES;
[self.view addSubview:overlay];
UIImageView *fullImageView = [[UIImageView alloc] initWithFrame:overlay.bounds];
fullImageView.contentMode = UIViewContentModeScaleAspectFit;
fullImageView.userInteractionEnabled = YES;
[overlay addSubview:fullImageView];
// Fetch the full-resolution image asynchronously
NSURL *url = [NSURL URLWithString:planFullURL];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *data = [NSData dataWithContentsOfURL:url];
if (data) {
UIImage *img = [UIImage imageWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
fullImageView.image = img;
});
}
});
UITapGestureRecognizer *dismissTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(closeFullFloorPlan)];
[overlay addGestureRecognizer:dismissTap];
[UIView animateWithDuration:0.25 animations:^{
overlay.alpha = 1;
}];
}
- (void)closeFullFloorPlan {
UIView *overlay = [self.view viewWithTag:901];
if (!overlay) return;
[UIView animateWithDuration:0.25 animations:^{
overlay.alpha = 0;
} completion:^(BOOL finished) {
[overlay removeFromSuperview];
}];
}
#pragma mark - Helper #pragma mark - Helper
- (UIColor *)colorFromHex:(NSString *)hexString { - (UIColor *)colorFromHex:(NSString *)hexString {
if (!hexString || hexString.length < 6) return [UIColor grayColor]; if (!hexString || hexString.length < 6) return [UIColor grayColor];
...@@ -414,7 +497,7 @@ ...@@ -414,7 +497,7 @@
HistoryViewController *nextVC = [[HistoryViewController alloc] init]; HistoryViewController *nextVC = [[HistoryViewController alloc] init];
nextVC.modalPresentationStyle = UIModalPresentationFullScreen; nextVC.modalPresentationStyle = UIModalPresentationFullScreen;
nextVC.issueID = self.issueData[@"issue_id"] ?: @""; nextVC.issueID = [NSString stringWithFormat:@"%@", self.issueData[@"issue_reference_id"] ?: self.issueData[@"id"] ?: @""];
nextVC.planID = self.issueData[@"plan_id"]; nextVC.planID = self.issueData[@"plan_id"];
nextVC.status = self.issueData[@"status_external"]; nextVC.status = self.issueData[@"status_external"];
nextVC.unitName = self.issueData[@"plan_unit"]; nextVC.unitName = self.issueData[@"plan_unit"];
......
...@@ -25,12 +25,13 @@ ...@@ -25,12 +25,13 @@
self.backgroundColor = UIColor.clearColor; self.backgroundColor = UIColor.clearColor;
UIView *card = [[UIView alloc] init]; UIView *card = [[UIView alloc] init];
card.backgroundColor = UIColor.whiteColor; card.layer.borderWidth = 1.0;
card.layer.cornerRadius = 12; card.layer.borderColor = [UIColor colorWithWhite:0.85 alpha:1.0].CGColor;
card.layer.shadowColor = [UIColor colorWithWhite:0 alpha:0.15].CGColor; card.layer.shadowColor = [UIColor colorWithWhite:0.0 alpha:0.2].CGColor;
card.layer.shadowOpacity = 0.1; card.layer.shadowOpacity = 0.25;
card.layer.shadowRadius = 3; card.layer.shadowRadius = 4;
card.layer.shadowOffset = CGSizeMake(0, 2); card.layer.shadowOffset = CGSizeMake(0, 2);
card.layer.masksToBounds = NO;
card.translatesAutoresizingMaskIntoConstraints = NO; card.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView addSubview:card]; [self.contentView addSubview:card];
...@@ -137,7 +138,7 @@ ...@@ -137,7 +138,7 @@
- (void)viewDidLoad { - (void)viewDidLoad {
[super viewDidLoad]; [super viewDidLoad];
self.view.backgroundColor = [UIColor systemGroupedBackgroundColor]; self.view.backgroundColor = [UIColor whiteColor];
[self setupHeader]; [self setupHeader];
[self setupFilterBar]; [self setupFilterBar];
[self setupSearchBar]; [self setupSearchBar];
...@@ -153,7 +154,8 @@ ...@@ -153,7 +154,8 @@
#pragma mark - Setup UI #pragma mark - Setup UI
- (void)setupHeader { - (void)setupHeader {
self.headerView = [[UIView alloc] init]; CGFloat statusBarHeight = UIApplication.sharedApplication.statusBarFrame.size.height;
self.headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, statusBarHeight + 60)];
self.headerView.translatesAutoresizingMaskIntoConstraints = NO; self.headerView.translatesAutoresizingMaskIntoConstraints = NO;
self.headerView.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0]; // THEME COLOR self.headerView.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0]; // THEME COLOR
[self.view addSubview:self.headerView]; [self.view addSubview:self.headerView];
...@@ -176,7 +178,7 @@ ...@@ -176,7 +178,7 @@
// Withdraw Button // Withdraw Button
self.withdrawButton = [UIButton buttonWithType:UIButtonTypeSystem]; self.withdrawButton = [UIButton buttonWithType:UIButtonTypeSystem];
[self.withdrawButton setImage:[UIImage systemImageNamed:@"tray.and.arrow.down"] forState:UIControlStateNormal]; [self.withdrawButton setImage:[UIImage systemImageNamed:@"checklist.checked"] forState:UIControlStateNormal];
self.withdrawButton.tintColor = UIColor.whiteColor; self.withdrawButton.tintColor = UIColor.whiteColor;
self.withdrawButton.translatesAutoresizingMaskIntoConstraints = NO; self.withdrawButton.translatesAutoresizingMaskIntoConstraints = NO;
[self.withdrawButton addTarget:self action:@selector(withdrawTapped) forControlEvents:UIControlEventTouchUpInside]; [self.withdrawButton addTarget:self action:@selector(withdrawTapped) forControlEvents:UIControlEventTouchUpInside];
...@@ -190,6 +192,7 @@ ...@@ -190,6 +192,7 @@
self.filterButton.layer.borderWidth = 0.5; self.filterButton.layer.borderWidth = 0.5;
self.filterButton.layer.borderColor = [UIColor lightGrayColor].CGColor; self.filterButton.layer.borderColor = [UIColor lightGrayColor].CGColor;
[self.filterButton setTitle:@"Filter: All" forState:UIControlStateNormal]; [self.filterButton setTitle:@"Filter: All" forState:UIControlStateNormal];
[self.filterButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
self.filterButton.tintColor = UIColor.labelColor; self.filterButton.tintColor = UIColor.labelColor;
self.filterButton.backgroundColor = UIColor.whiteColor; self.filterButton.backgroundColor = UIColor.whiteColor;
self.filterButton.titleLabel.font = [UIFont systemFontOfSize:15]; self.filterButton.titleLabel.font = [UIFont systemFontOfSize:15];
...@@ -205,6 +208,35 @@ ...@@ -205,6 +208,35 @@
self.searchBar.autocapitalizationType = UITextAutocapitalizationTypeNone; self.searchBar.autocapitalizationType = UITextAutocapitalizationTypeNone;
self.searchBar.autocorrectionType = UITextAutocorrectionTypeNo; self.searchBar.autocorrectionType = UITextAutocorrectionTypeNo;
self.searchBar.returnKeyType = UIReturnKeyDone; self.searchBar.returnKeyType = UIReturnKeyDone;
self.searchBar.showsCancelButton = YES;
self.searchBar.barTintColor = [UIColor whiteColor];
self.searchBar.backgroundImage = [UIImage new];
self.searchBar.opaque = YES;
// ✅ Customize the internal text field
UITextField *textField = [self.searchBar valueForKey:@"searchField"];
if (textField) {
textField.textColor = [UIColor blackColor];
textField.tintColor = [UIColor darkGrayColor];
textField.backgroundColor = [UIColor whiteColor];
textField.layer.borderColor = [UIColor lightGrayColor].CGColor;
textField.layer.borderWidth = 1.0;
textField.layer.cornerRadius = 8.0;
textField.clipsToBounds = YES;
textField.attributedPlaceholder = [[NSAttributedString alloc]
initWithString:self.searchBar.placeholder
attributes:@{NSForegroundColorAttributeName: [UIColor grayColor]}];
}
UIButton *cancelButton = [self.searchBar valueForKey:@"cancelButton"];
if (cancelButton) {
[cancelButton setTitleColor:[UIColor systemBlueColor] forState:UIControlStateNormal];
[cancelButton setTitleColor:[UIColor grayColor] forState:UIControlStateHighlighted];
cancelButton.titleLabel.font = [UIFont boldSystemFontOfSize:16];
}
[self.view addSubview:self.searchBar]; [self.view addSubview:self.searchBar];
} }
...@@ -213,6 +245,9 @@ ...@@ -213,6 +245,9 @@
self.tableView.translatesAutoresizingMaskIntoConstraints = NO; self.tableView.translatesAutoresizingMaskIntoConstraints = NO;
self.tableView.delegate = self; self.tableView.delegate = self;
self.tableView.dataSource = self; self.tableView.dataSource = self;
self.tableView.backgroundView = nil;
self.tableView.backgroundColor = [UIColor whiteColor];
self.tableView.opaque = YES;
[self.tableView registerClass:[IssueCell class] forCellReuseIdentifier:@"IssueCell"]; [self.tableView registerClass:[IssueCell class] forCellReuseIdentifier:@"IssueCell"];
// 🔹 Section header behavior // 🔹 Section header behavior
...@@ -332,10 +367,21 @@ ...@@ -332,10 +367,21 @@
NSString *reference = [issue[@"reference"] ?: @"" uppercaseString]; NSString *reference = [issue[@"reference"] ?: @"" uppercaseString];
NSString *location = [issue[@"location_name"] ?: @"" uppercaseString]; NSString *location = [issue[@"location_name"] ?: @"" uppercaseString];
NSString *remarks = [issue[@"remarks"] ?: @"" uppercaseString]; NSString *remarks = [issue[@"remarks"] ?: @"" uppercaseString];
NSString *createdAt = [issue[@"created_at"] ?: @"" uppercaseString];
NSString *category = [issue[@"category"] ?: @"" uppercaseString];
NSString *type = [issue[@"type"] ?: @"" uppercaseString];
NSString *issueText = [issue[@"issue"] ?: @"" uppercaseString];
NSString *status = [issue[@"status_external"] ?: @"" uppercaseString];
if ([reference containsString:search] || if ([reference containsString:search] ||
[location containsString:search] || [location containsString:search] ||
[remarks containsString:search]) { [remarks containsString:search] ||
[createdAt containsString:search] ||
[category containsString:search] ||
[type containsString:search] ||
[issueText containsString:search] ||
[status containsString:search]) {
[matches addObject:issue]; [matches addObject:issue];
} }
} }
...@@ -678,4 +724,21 @@ ...@@ -678,4 +724,21 @@
[self presentViewController:detailVC animated:YES completion:nil]; [self presentViewController:detailVC animated:YES completion:nil];
} }
#pragma mark - UISearchBarDelegate
-(void)searchbar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
[self applySearch:searchText];
}
-(void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
[searchBar resignFirstResponder];
[self applySearch:searchBar.text];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
// Optional: reset search when user cancels
[searchBar resignFirstResponder];
searchBar.text = @"";
[self applySearch:@""];
}
@end @end
...@@ -3,9 +3,153 @@ ...@@ -3,9 +3,153 @@
#import "IssueAPIClient.h" #import "IssueAPIClient.h"
#import "WithdrawSingleIssueViewController.h" #import "WithdrawSingleIssueViewController.h"
#pragma mark - custom cell structure
@interface WithdrawIssueCell : UITableViewCell
@property (nonatomic, strong) UIImageView *thumbView;
@property (nonatomic, strong) UILabel *referenceLabel;
@property (nonatomic, strong) UILabel *statusLabel;
@property (nonatomic, strong) UILabel *locationLabel;
@property (nonatomic, strong) UILabel *createdLabel;
@property (nonatomic, strong) UILabel *detailsLabel;
@property (nonatomic, strong) UIImageView *checkmarkView;
@end
@implementation WithdrawIssueCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.backgroundColor = UIColor.clearColor;
self.selectionStyle = UITableViewCellSelectionStyleNone;
UIView *card = [[UIView alloc] init];
card.backgroundColor = UIColor.whiteColor;
card.layer.cornerRadius = 12;
card.layer.shadowColor = [UIColor blackColor].CGColor;
card.layer.shadowOpacity = 0.1;
card.layer.shadowOffset = CGSizeMake(0, 2);
card.layer.shadowRadius = 4;
card.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView addSubview:card];
// Tick/checkmark icon
_checkmarkView = [[UIImageView alloc] initWithImage:[UIImage systemImageNamed:@"circle"]];
_checkmarkView.tintColor = [UIColor lightGrayColor];
_checkmarkView.translatesAutoresizingMaskIntoConstraints = NO;
_checkmarkView.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView addSubview:_checkmarkView];
// Thumbnail
_thumbView = [[UIImageView alloc] init];
_thumbView.translatesAutoresizingMaskIntoConstraints = NO;
_thumbView.layer.cornerRadius = 25;
_thumbView.layer.masksToBounds = YES;
_thumbView.contentMode = UIViewContentModeScaleAspectFill;
[card addSubview:_thumbView];
// Labels
_referenceLabel = [[UILabel alloc] init];
_referenceLabel.font = [UIFont boldSystemFontOfSize:16];
_referenceLabel.translatesAutoresizingMaskIntoConstraints = NO;
[card addSubview:_referenceLabel];
_statusLabel = [[UILabel alloc] init];
_statusLabel.font = [UIFont systemFontOfSize:12 weight:UIFontWeightMedium];
_statusLabel.textColor = UIColor.whiteColor;
_statusLabel.backgroundColor = [UIColor systemTealColor];
_statusLabel.layer.cornerRadius = 6;
_statusLabel.layer.masksToBounds = YES;
_statusLabel.textAlignment = NSTextAlignmentCenter;
_statusLabel.translatesAutoresizingMaskIntoConstraints = NO;
[card addSubview:_statusLabel];
_locationLabel = [[UILabel alloc] init];
_locationLabel.font = [UIFont systemFontOfSize:14];
_locationLabel.textColor = UIColor.darkGrayColor;
_locationLabel.translatesAutoresizingMaskIntoConstraints = NO;
[card addSubview:_locationLabel];
_createdLabel = [[UILabel alloc] init];
_createdLabel.font = [UIFont systemFontOfSize:12];
_createdLabel.textColor = UIColor.grayColor;
_createdLabel.translatesAutoresizingMaskIntoConstraints = NO;
[card addSubview:_createdLabel];
_detailsLabel = [[UILabel alloc] init];
_detailsLabel.font = [UIFont systemFontOfSize:13];
_detailsLabel.textColor = [UIColor grayColor];
_detailsLabel.numberOfLines = 2;
_detailsLabel.translatesAutoresizingMaskIntoConstraints = NO;
[card addSubview:_detailsLabel];
// Layout
[NSLayoutConstraint activateConstraints:@[
// Checkmark
[_checkmarkView.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:10],
[_checkmarkView.centerYAnchor constraintEqualToAnchor:self.contentView.centerYAnchor],
[_checkmarkView.widthAnchor constraintEqualToConstant:28],
[_checkmarkView.heightAnchor constraintEqualToConstant:28],
// Card itself
[card.leadingAnchor constraintEqualToAnchor:_checkmarkView.trailingAnchor constant:6],
[card.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-8],
[card.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:4],
[card.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor constant:-4],
// Thumbnail
[_thumbView.leadingAnchor constraintEqualToAnchor:card.leadingAnchor constant:12],
[_thumbView.topAnchor constraintEqualToAnchor:card.topAnchor constant:12],
[_thumbView.widthAnchor constraintEqualToConstant:50],
[_thumbView.heightAnchor constraintEqualToConstant:50],
// Reference
[_referenceLabel.topAnchor constraintEqualToAnchor:card.topAnchor constant:12],
[_referenceLabel.leadingAnchor constraintEqualToAnchor:_thumbView.trailingAnchor constant:12],
[_referenceLabel.trailingAnchor constraintLessThanOrEqualToAnchor:_statusLabel.leadingAnchor constant:-8],
// Status
[_statusLabel.centerYAnchor constraintEqualToAnchor:_locationLabel.centerYAnchor],
[_statusLabel.trailingAnchor constraintEqualToAnchor:card.trailingAnchor constant:-12],
[_statusLabel.widthAnchor constraintGreaterThanOrEqualToConstant:60],
[_statusLabel.heightAnchor constraintEqualToConstant:22],
// Location
[_locationLabel.topAnchor constraintEqualToAnchor:_referenceLabel.bottomAnchor constant:4],
[_locationLabel.leadingAnchor constraintEqualToAnchor:_thumbView.trailingAnchor constant:12],
[_locationLabel.trailingAnchor constraintEqualToAnchor:card.trailingAnchor constant:-12],
// Created
[_createdLabel.topAnchor constraintEqualToAnchor:_locationLabel.bottomAnchor constant:4],
[_createdLabel.leadingAnchor constraintEqualToAnchor:_thumbView.trailingAnchor constant:12],
[_createdLabel.trailingAnchor constraintEqualToAnchor:card.trailingAnchor constant:-12],
// Details (at bottom)
[_detailsLabel.topAnchor constraintEqualToAnchor:_createdLabel.bottomAnchor constant:4],
[_detailsLabel.leadingAnchor constraintEqualToAnchor:_thumbView.trailingAnchor constant:12],
[_detailsLabel.trailingAnchor constraintEqualToAnchor:card.trailingAnchor constant:-12],
[_detailsLabel.bottomAnchor constraintEqualToAnchor:card.bottomAnchor constant:-12],
]];
}
return self;
}
- (void)updateSelectionState:(BOOL)isSelected {
self.checkmarkView.image = isSelected
? [UIImage systemImageNamed:@"checkmark.circle.fill"]
: [UIImage systemImageNamed:@"circle"];
self.checkmarkView.tintColor = isSelected
? [UIColor systemTealColor]
: [UIColor lightGrayColor];
self.contentView.alpha = isSelected ? 0.85 : 1.0;
}
@end
#pragma mark - view controller
@interface WithdrawIssuesViewController () <UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate> @interface WithdrawIssuesViewController () <UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate>
@property (nonatomic, strong) UIButton *closeButton; @property (nonatomic, strong) UIButton *backButton;
@property (nonatomic, strong) UILabel *titleLabel; @property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UISearchBar *searchBar; @property (nonatomic, strong) UISearchBar *searchBar;
@property (nonatomic, strong) UIButton *filterButton; @property (nonatomic, strong) UIButton *filterButton;
...@@ -13,8 +157,7 @@ ...@@ -13,8 +157,7 @@
@property (nonatomic, strong) UITableView *tableView; @property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) UILabel *counterLabel; @property (nonatomic, strong) UILabel *counterLabel;
@property (nonatomic, strong) UIButton *proceedButton; @property (nonatomic, strong) UIButton *proceedButton;
@property (nonatomic, strong) UIView *searchContainer;
@property (nonatomic, strong) UIView *bottomBar;
@property (nonatomic, strong) NSArray *issues; @property (nonatomic, strong) NSArray *issues;
@property (nonatomic, strong) NSMutableSet *selectedIssueIDs; @property (nonatomic, strong) NSMutableSet *selectedIssueIDs;
@property (nonatomic, strong) NSArray *filteredIssues; @property (nonatomic, strong) NSArray *filteredIssues;
...@@ -25,7 +168,7 @@ ...@@ -25,7 +168,7 @@
- (void)viewDidLoad { - (void)viewDidLoad {
[super viewDidLoad]; [super viewDidLoad];
self.view.backgroundColor = UIColor.systemGroupedBackgroundColor; self.view.backgroundColor = UIColor.whiteColor;
self.selectedIssueIDs = [NSMutableSet set]; self.selectedIssueIDs = [NSMutableSet set];
[self setupHeader]; [self setupHeader];
...@@ -35,19 +178,47 @@ ...@@ -35,19 +178,47 @@
[self fetchIssues]; [self fetchIssues];
} }
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
static BOOL hasLoadedBefore = NO;
if (!hasLoadedBefore) {
hasLoadedBefore = YES;
[self.selectedIssueIDs removeAllObjects];
[self.tableView reloadData];
} else if (self.isMovingToParentViewController) {
// Coming here via push (forward navigation)
[self.selectedIssueIDs removeAllObjects];
[self.tableView reloadData];
}
}
#pragma mark - UI Setup #pragma mark - UI Setup
- (void)setupHeader { - (void)setupHeader {
UIView *statusBarBackground = [[UIView alloc] init];
statusBarBackground.backgroundColor = [UIColor colorWithRed:0/255.0
green:109/255.0
blue:141/255.0
alpha:1];
statusBarBackground.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:statusBarBackground];
UIView *header = [[UIView alloc] init]; UIView *header = [[UIView alloc] init];
header.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0]; header.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0];
header.translatesAutoresizingMaskIntoConstraints = NO; header.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:header]; [self.view addSubview:header];
self.closeButton = [UIButton buttonWithType:UIButtonTypeSystem]; // Back button
[self.closeButton setImage:[UIImage systemImageNamed:@"xmark"] forState:UIControlStateNormal]; self.backButton = [UIButton buttonWithType:UIButtonTypeSystem];
self.closeButton.tintColor = UIColor.whiteColor; self.backButton.translatesAutoresizingMaskIntoConstraints = NO;
[self.closeButton addTarget:self action:@selector(closeTapped) forControlEvents:UIControlEventTouchUpInside]; UIImage *backImage = [[UIImage systemImageNamed:@"chevron.left"]
self.closeButton.translatesAutoresizingMaskIntoConstraints = NO; imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[header addSubview:self.closeButton]; [self.backButton setImage:backImage forState:UIControlStateNormal];
self.backButton.tintColor = UIColor.whiteColor;
[self.backButton addTarget:self
action:@selector(handleBack)
forControlEvents:UIControlEventTouchUpInside];
[header addSubview:self.backButton];
self.titleLabel = [[UILabel alloc] init]; self.titleLabel = [[UILabel alloc] init];
self.titleLabel.text = @"Withdraw Issue"; self.titleLabel.text = @"Withdraw Issue";
...@@ -62,8 +233,8 @@ ...@@ -62,8 +233,8 @@
[header.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], [header.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[header.heightAnchor constraintEqualToConstant:50], [header.heightAnchor constraintEqualToConstant:50],
[self.closeButton.leadingAnchor constraintEqualToAnchor:header.leadingAnchor constant:16], [self.backButton.leadingAnchor constraintEqualToAnchor:header.leadingAnchor constant:16],
[self.closeButton.centerYAnchor constraintEqualToAnchor:header.centerYAnchor], [self.backButton.centerYAnchor constraintEqualToAnchor:header.centerYAnchor],
[self.titleLabel.centerXAnchor constraintEqualToAnchor:header.centerXAnchor], [self.titleLabel.centerXAnchor constraintEqualToAnchor:header.centerXAnchor],
[self.titleLabel.centerYAnchor constraintEqualToAnchor:header.centerYAnchor], [self.titleLabel.centerYAnchor constraintEqualToAnchor:header.centerYAnchor],
...@@ -71,71 +242,120 @@ ...@@ -71,71 +242,120 @@
} }
- (void)setupSearchBar { - (void)setupSearchBar {
self.searchContainer = [[UIView alloc] init]; // 👈 keep a property reference UIView *searchContainer = [[UIView alloc] init];
self.searchContainer.translatesAutoresizingMaskIntoConstraints = NO; searchContainer.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.searchContainer]; [self.view addSubview:searchContainer];
self.searchBar = [[UISearchBar alloc] init]; self.searchBar = [[UISearchBar alloc] init];
self.searchBar.placeholder = @"Search Reference Number / Location"; self.searchBar.placeholder = @"Search Reference Number / Location";
self.searchBar.delegate = self; self.searchBar.delegate = self;
self.searchBar.translatesAutoresizingMaskIntoConstraints = NO; self.searchBar.translatesAutoresizingMaskIntoConstraints = NO;
[self.searchContainer addSubview:self.searchBar]; self.searchBar.showsCancelButton = YES;
self.searchBar.barTintColor = [UIColor whiteColor];
self.searchBar.backgroundImage = [UIImage new]; // removes dark/blurred bg
if (@available(iOS 13.0, *)) {
self.searchBar.searchTextField.backgroundColor = [UIColor whiteColor];
self.searchBar.searchTextField.textColor = [UIColor blackColor];
}
self.searchBar.opaque = YES;
[searchContainer addSubview:self.searchBar];
self.selectAllButton = [UIButton buttonWithType:UIButtonTypeSystem]; self.selectAllButton = [UIButton buttonWithType:UIButtonTypeSystem];
[self.selectAllButton setTitle:@"Select All" forState:UIControlStateNormal]; [self.selectAllButton setTitle:@"Select All" forState:UIControlStateNormal];
[self.selectAllButton setTitleColor:[UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0] forState:UIControlStateNormal]; [self.selectAllButton setTitleColor:[UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0] forState:UIControlStateNormal];
self.selectAllButton.translatesAutoresizingMaskIntoConstraints = NO; self.selectAllButton.translatesAutoresizingMaskIntoConstraints = NO;
[self.selectAllButton addTarget:self action:@selector(selectAllTapped) forControlEvents:UIControlEventTouchUpInside]; [self.selectAllButton addTarget:self action:@selector(selectAllTapped) forControlEvents:UIControlEventTouchUpInside];
[self.searchContainer addSubview:self.selectAllButton]; [searchContainer addSubview:self.selectAllButton];
UIView *header = self.view.subviews.firstObject;
[NSLayoutConstraint activateConstraints:@[ [NSLayoutConstraint activateConstraints:@[
[self.searchContainer.topAnchor constraintEqualToAnchor:header.bottomAnchor], [searchContainer.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor constant:50],
[self.searchContainer.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:8], [searchContainer.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:8],
[self.searchContainer.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-8], [searchContainer.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-8],
[self.searchContainer.heightAnchor constraintEqualToConstant:80], [searchContainer.heightAnchor constraintEqualToConstant:100],
[self.searchBar.leadingAnchor constraintEqualToAnchor:self.searchContainer.leadingAnchor], [self.searchBar.leadingAnchor constraintEqualToAnchor:searchContainer.leadingAnchor],
[self.searchBar.trailingAnchor constraintEqualToAnchor:self.searchContainer.trailingAnchor constant:-8], [self.searchBar.trailingAnchor constraintEqualToAnchor:searchContainer.trailingAnchor],
[self.searchBar.centerYAnchor constraintEqualToAnchor:self.searchContainer.centerYAnchor constant:-10], [self.searchBar.centerYAnchor constraintEqualToAnchor:searchContainer.centerYAnchor constant:-10],
[self.selectAllButton.trailingAnchor constraintEqualToAnchor:self.searchContainer.trailingAnchor constant:-16], [self.selectAllButton.trailingAnchor constraintEqualToAnchor:searchContainer.trailingAnchor constant:-16],
[self.selectAllButton.topAnchor constraintEqualToAnchor:self.searchBar.bottomAnchor constant:8], [self.selectAllButton.topAnchor constraintEqualToAnchor:self.searchBar.bottomAnchor constant:8],
]]; ]];
UITextField *textField = self.searchBar.searchTextField;
// Make text darker and clearer
textField.textColor = [UIColor blackColor];
textField.font = [UIFont systemFontOfSize:16 weight:UIFontWeightRegular];
// Darken placeholder
textField.attributedPlaceholder = [[NSAttributedString alloc]
initWithString:self.searchBar.placeholder
attributes:@{NSForegroundColorAttributeName: [UIColor darkGrayColor],
NSFontAttributeName: [UIFont systemFontOfSize:16]}];
// Optional: give the search field a white rounded background with shadow
textField.backgroundColor = [UIColor whiteColor];
textField.layer.cornerRadius = 10;
textField.layer.masksToBounds = YES;
textField.layer.borderColor = [UIColor colorWithWhite:0.8 alpha:1.0].CGColor; // light gray
textField.layer.borderWidth = 1.0;
} }
- (void)setupTableView { - (void)setupTableView {
self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain]; self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
self.tableView.translatesAutoresizingMaskIntoConstraints = NO; self.tableView.translatesAutoresizingMaskIntoConstraints = NO;
self.tableView.backgroundColor = [UIColor systemGroupedBackgroundColor];
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
self.tableView.delegate = self; self.tableView.delegate = self;
self.tableView.dataSource = self; self.tableView.dataSource = self;
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
self.tableView.backgroundView = nil;
self.tableView.backgroundColor = [UIColor whiteColor];
self.tableView.opaque = YES;
[self.tableView registerClass:[WithdrawIssueCell class] forCellReuseIdentifier:@"WithdrawIssueCell"];
[self.view addSubview:self.tableView]; [self.view addSubview:self.tableView];
}
- (void)setupBottomBar {
self.bottomBar = [[UIView alloc] init]; // 👈 also store in a property
self.bottomBar.backgroundColor = UIColor.whiteColor;
self.bottomBar.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.bottomBar];
// ... your existing counter + button setup ... [NSLayoutConstraint activateConstraints:@[
[self.tableView.topAnchor constraintEqualToAnchor:self.searchBar.superview.bottomAnchor constant:4],
[self.tableView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:8],
[self.tableView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-8],
[self.tableView.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor constant:-60]
]];
} }
- (void)viewDidLayoutSubviews { - (void)setupBottomBar {
[super viewDidLayoutSubviews]; UIView *bottomBar = [[UIView alloc] init];
bottomBar.backgroundColor = UIColor.whiteColor;
bottomBar.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:bottomBar];
self.counterLabel = [[UILabel alloc] init];
self.counterLabel.text = @"0 / 0";
self.counterLabel.font = [UIFont systemFontOfSize:14 weight:UIFontWeightMedium];
self.counterLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.counterLabel.textColor = UIColor.blackColor;
[bottomBar addSubview:self.counterLabel];
self.proceedButton = [UIButton buttonWithType:UIButtonTypeSystem];
[self.proceedButton setTitle:@"Proceed" forState:UIControlStateNormal];
self.proceedButton.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0];
[self.proceedButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
self.proceedButton.layer.cornerRadius = 8;
self.proceedButton.translatesAutoresizingMaskIntoConstraints = NO;
[self.proceedButton addTarget:self action:@selector(proceedTapped) forControlEvents:UIControlEventTouchUpInside];
[bottomBar addSubview:self.proceedButton];
// Now that everything exists, activate proper constraints for the table
if (self.tableView.constraints.count == 0) {
[NSLayoutConstraint activateConstraints:@[ [NSLayoutConstraint activateConstraints:@[
[self.tableView.topAnchor constraintEqualToAnchor:self.searchContainer.bottomAnchor constant:8], [bottomBar.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.tableView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], [bottomBar.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.tableView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], [bottomBar.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor],
[self.tableView.bottomAnchor constraintEqualToAnchor:self.bottomBar.topAnchor] [bottomBar.heightAnchor constraintEqualToConstant:60],
[self.counterLabel.leadingAnchor constraintEqualToAnchor:bottomBar.leadingAnchor constant:16],
[self.counterLabel.centerYAnchor constraintEqualToAnchor:bottomBar.centerYAnchor],
[self.proceedButton.trailingAnchor constraintEqualToAnchor:bottomBar.trailingAnchor constant:-16],
[self.proceedButton.centerYAnchor constraintEqualToAnchor:bottomBar.centerYAnchor],
[self.proceedButton.widthAnchor constraintEqualToConstant:120],
[self.proceedButton.heightAnchor constraintEqualToConstant:40]
]]; ]];
}
} }
#pragma mark - Data #pragma mark - Data
...@@ -145,12 +365,8 @@ ...@@ -145,12 +365,8 @@
NSArray *allIssues = data[@"Data"] ?: @[]; NSArray *allIssues = data[@"Data"] ?: @[];
// ✅ Filter W.I.P. only // ✅ Filter to show only "W.I.P" issues
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(NSDictionary *issue, NSDictionary *bindings) { NSPredicate *predicate = [NSPredicate predicateWithFormat:@"status_external == %@", @"W.I.P"];
NSString *status = [issue[@"status_external"] lowercaseString];
return [status isEqualToString:@"w.i.p"] || [status isEqualToString:@"wip"];
}];
self.issues = [allIssues filteredArrayUsingPredicate:predicate]; self.issues = [allIssues filteredArrayUsingPredicate:predicate];
self.filteredIssues = self.issues; self.filteredIssues = self.issues;
...@@ -161,31 +377,61 @@ ...@@ -161,31 +377,61 @@
}]; }];
} }
#pragma mark - Actions #pragma mark - Actions
- (void)closeTapped { - (void)handleBack {
[self dismissViewControllerAnimated:YES completion:nil]; [self dismissViewControllerAnimated:YES completion:nil];
} }
- (void)selectAllTapped { - (void)selectAllTapped {
if (self.selectedIssueIDs.count == self.issues.count) { if (self.selectedIssueIDs.count == self.filteredIssues.count) {
// All visible issues are selected, so deselect all
[self.selectedIssueIDs removeAllObjects]; [self.selectedIssueIDs removeAllObjects];
} else { } else {
for (NSDictionary *issue in self.issues) { // Select all currently visible issues
for (NSDictionary *issue in self.filteredIssues) {
[self.selectedIssueIDs addObject:issue[@"id"]]; [self.selectedIssueIDs addObject:issue[@"id"]];
} }
} }
// Update button title dynamically
if (self.selectedIssueIDs.count == self.filteredIssues.count) {
[self.selectAllButton setTitle:@"Deselect All" forState:UIControlStateNormal];
} else {
[self.selectAllButton setTitle:@"Select All" forState:UIControlStateNormal];
}
[self.tableView reloadData]; [self.tableView reloadData];
[self updateCounter]; [self updateCounter];
} }
- (void)proceedTapped { - (void)proceedTapped {
if (self.selectedIssueIDs.count == 0) { if (self.selectedIssueIDs.count == 0) {
[self showAlert:@"Please select at least one issue to proceed."]; [self showAlert:@"Please select at least one issue to proceed."];
return; return;
} }
NSPredicate *selectedPredicate = [NSPredicate predicateWithFormat:@"id IN %@", self.selectedIssueIDs];
NSArray *filteredIssues = [self.issues filteredArrayUsingPredicate:selectedPredicate];
NSLog(@"✅ Selected issue IDs: %@", self.selectedIssueIDs);
NSLog(@"✅ Total issues available: %lu", (unsigned long)self.issues.count);
NSLog(@"✅ Filtered selected issues: %@", filteredIssues);
// Create a clean array with only the reference (and other desired fields)
NSMutableArray *formattedIssues = [NSMutableArray array];
for (NSDictionary *issue in filteredIssues) {
NSString *ref = issue[@"reference"] ?: @"";
NSString *issueId = issue[@"id"] ?: @"";
[formattedIssues addObject:@{
@"id": issueId,
@"reference": ref
}];
}
NSLog(@"✅ Final selectedIssues to send: %@", formattedIssues);
WithdrawSingleIssueViewController *vc = [[WithdrawSingleIssueViewController alloc] init]; WithdrawSingleIssueViewController *vc = [[WithdrawSingleIssueViewController alloc] init];
vc.selectedIssues = [self.issues filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"id IN %@", self.selectedIssueIDs]]; vc.selectedIssues = formattedIssues; // Clean, predictable structure
vc.isMultiWithdraw = YES; vc.isMultiWithdraw = YES;
vc.modalPresentationStyle = UIModalPresentationFullScreen; vc.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:vc animated:YES completion:nil]; [self presentViewController:vc animated:YES completion:nil];
...@@ -201,93 +447,43 @@ ...@@ -201,93 +447,43 @@
[self presentViewController:alert animated:YES completion:nil]; [self presentViewController:alert animated:YES completion:nil];
} }
#pragma mark - TableView - (void)setNoImagePlaceholder:(UIImageView *)thumbView {
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // Clear any previous content
return self.filteredIssues.count; thumbView.image = nil;
} thumbView.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1.0];
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellId = @"WithdrawCardCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];
cell.backgroundColor = UIColor.clearColor;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
// --- Card container ---
UIView *card = [[UIView alloc] initWithFrame:CGRectZero];
card.tag = 100;
card.backgroundColor = UIColor.whiteColor;
card.layer.cornerRadius = 12;
card.layer.shadowColor = [UIColor blackColor].CGColor;
card.layer.shadowOpacity = 0.1;
card.layer.shadowRadius = 4;
card.layer.shadowOffset = CGSizeMake(0, 2);
[cell.contentView addSubview:card];
card.translatesAutoresizingMaskIntoConstraints = NO;
// --- Checkmark overlay --- for (UIView *subview in thumbView.subviews) {
UIImageView *checkIcon = [[UIImageView alloc] initWithImage:[UIImage systemImageNamed:@"checkmark.circle.fill"]]; [subview removeFromSuperview];
checkIcon.tag = 202;
checkIcon.tintColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0];
checkIcon.translatesAutoresizingMaskIntoConstraints = NO;
[cell.contentView addSubview:checkIcon];
// --- Title ---
UILabel *titleLabel = [[UILabel alloc] init];
titleLabel.tag = 200;
titleLabel.font = [UIFont boldSystemFontOfSize:16];
[card addSubview:titleLabel];
titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
// --- Subtitle ---
UILabel *subtitleLabel = [[UILabel alloc] init];
subtitleLabel.tag = 201;
subtitleLabel.font = [UIFont systemFontOfSize:14];
subtitleLabel.textColor = UIColor.darkGrayColor;
[card addSubview:subtitleLabel];
subtitleLabel.translatesAutoresizingMaskIntoConstraints = NO;
// --- Layout ---
[NSLayoutConstraint activateConstraints:@[
[card.leadingAnchor constraintEqualToAnchor:cell.contentView.leadingAnchor constant:16],
[card.trailingAnchor constraintEqualToAnchor:cell.contentView.trailingAnchor constant:-32], // leave space on the right for the checkmark
[card.topAnchor constraintEqualToAnchor:cell.contentView.topAnchor],
[card.bottomAnchor constraintEqualToAnchor:cell.contentView.bottomAnchor constant:-4],
[checkIcon.centerYAnchor constraintEqualToAnchor:card.centerYAnchor],
[checkIcon.leadingAnchor constraintEqualToAnchor:card.trailingAnchor constant:4], // positioned outside the card
[checkIcon.widthAnchor constraintEqualToConstant:28],
[checkIcon.heightAnchor constraintEqualToConstant:28],
[titleLabel.topAnchor constraintEqualToAnchor:card.topAnchor constant:12],
[titleLabel.leadingAnchor constraintEqualToAnchor:card.leadingAnchor constant:12],
[titleLabel.trailingAnchor constraintLessThanOrEqualToAnchor:card.trailingAnchor constant:-12],
[subtitleLabel.topAnchor constraintEqualToAnchor:titleLabel.bottomAnchor constant:4],
[subtitleLabel.leadingAnchor constraintEqualToAnchor:card.leadingAnchor constant:12],
[subtitleLabel.trailingAnchor constraintEqualToAnchor:card.trailingAnchor constant:-12],
[subtitleLabel.bottomAnchor constraintEqualToAnchor:card.bottomAnchor constant:-12]
]];
} }
// --- Configure cell --- UILabel *noImageLabel = [[UILabel alloc] init];
NSDictionary *issue = self.filteredIssues[indexPath.row]; noImageLabel.text = @"No image";
UILabel *titleLabel = [cell.contentView viewWithTag:200]; noImageLabel.textAlignment = NSTextAlignmentCenter;
UILabel *subtitleLabel = [cell.contentView viewWithTag:201]; noImageLabel.font = [UIFont systemFontOfSize:10];
UIImageView *checkIcon = [cell.contentView viewWithTag:202]; noImageLabel.textColor = [UIColor grayColor];
noImageLabel.translatesAutoresizingMaskIntoConstraints = NO;
titleLabel.text = issue[@"location_name"]; [thumbView addSubview:noImageLabel];
subtitleLabel.text = [NSString stringWithFormat:@"%@ → %@", issue[@"category"], issue[@"issue"]];
BOOL isSelected = [self.selectedIssueIDs containsObject:issue[@"id"]]; [NSLayoutConstraint activateConstraints:@[
checkIcon.hidden = !isSelected; [noImageLabel.centerXAnchor constraintEqualToAnchor:thumbView.centerXAnchor],
[noImageLabel.centerYAnchor constraintEqualToAnchor:thumbView.centerYAnchor]
]];
}
return cell; - (UIColor *)colorFromHexString:(NSString *)hex {
unsigned int rgbValue = 0;
NSScanner *scanner = [NSScanner scannerWithString:hex];
if ([hex hasPrefix:@"#"]) [scanner setScanLocation:1];
[scanner scanHexInt:&rgbValue];
return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16) / 255.0
green:((rgbValue & 0xFF00) >> 8) / 255.0
blue:(rgbValue & 0xFF) / 255.0
alpha:1.0];
} }
#pragma mark - TableView
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSDictionary *issue = self.filteredIssues[indexPath.row]; NSDictionary *issue = self.filteredIssues[indexPath.section];
NSString *issueID = issue[@"id"]; NSString *issueID = issue[@"id"];
if ([self.selectedIssueIDs containsObject:issueID]) { if ([self.selectedIssueIDs containsObject:issueID]) {
...@@ -295,22 +491,163 @@ ...@@ -295,22 +491,163 @@
} else { } else {
[self.selectedIssueIDs addObject:issueID]; [self.selectedIssueIDs addObject:issueID];
} }
[self updateCounter]; [self updateCounter];
[tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
WithdrawIssueCell *cell = [tableView cellForRowAtIndexPath:indexPath];
BOOL isSelected = [self.selectedIssueIDs containsObject:issueID];
[cell updateSelectionState:isSelected];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return self.filteredIssues.count;
} }
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 100; // adjust to your card height return 1;
} }
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
WithdrawIssueCell *cell = [tableView dequeueReusableCellWithIdentifier:@"WithdrawIssueCell" forIndexPath:indexPath];
// Reset reused state
cell.thumbView.image = nil;
for (UIView *subview in cell.thumbView.subviews) {
[subview removeFromSuperview];
}
NSDictionary *issue = self.filteredIssues[indexPath.section];
NSString *thumbURL = issue[@"thumb_image"] ?: @"";
// Thumbnail rendering (copied from IssueViewController)
if (thumbURL.length > 0) {
NSURL *url = [NSURL URLWithString:thumbURL];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *data = [NSData dataWithContentsOfURL:url];
dispatch_async(dispatch_get_main_queue(), ^{
WithdrawIssueCell *updateCell = [tableView cellForRowAtIndexPath:indexPath];
if (!updateCell) return;
// Clear any "No image" placeholder labels
for (UIView *subview in updateCell.thumbView.subviews) {
[subview removeFromSuperview];
}
if (data) {
UIImage *img = [UIImage imageWithData:data];
if (img) {
updateCell.thumbView.image = img;
updateCell.thumbView.backgroundColor = UIColor.clearColor;
} else {
[self setNoImagePlaceholder:updateCell.thumbView];
}
} else {
[self setNoImagePlaceholder:updateCell.thumbView];
}
});
});
} else {
[self setNoImagePlaceholder:cell.thumbView];
}
// Text fields
cell.referenceLabel.text = issue[@"reference"] ?: @"";
cell.statusLabel.text = issue[@"status_external"] ?: @"";
cell.statusLabel.backgroundColor = [self colorFromHexString:issue[@"status_ex_color"] ?: @""];
cell.locationLabel.text = issue[@"location_name"] ?: @"";
cell.createdLabel.text = [NSString stringWithFormat:@"Created on %@", issue[@"created_at"] ?: @""];
NSString *category = issue[@"category"] ?: @"";
NSString *type = issue[@"type"] ?: @"";
NSString *issueText = issue[@"issue"] ?: @"";
cell.detailsLabel.text = [NSString stringWithFormat:@"%@ → %@ → %@",
category, type, issueText];
// Highlight selected ones
BOOL isSelected = [self.selectedIssueIDs containsObject:issue[@"id"]];
[cell updateSelectionState:isSelected];
return cell;
}
// ✅ Add spacing between cells using header/footer height
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 10; // spacing between cells return 2; // top spacing
} }
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
return 2; // bottom spacing
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
return 110;
}
// Remove empty header/footer lines at end
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView *spacer = [[UIView alloc] init]; return [UIView new];
spacer.backgroundColor = UIColor.clearColor; }
return spacer;
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
return [UIView new];
}
#pragma mark - Search Handling
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
NSString *search = [searchText uppercaseString];
if (search.length == 0) {
self.filteredIssues = self.issues;
} else {
NSMutableArray *matches = [NSMutableArray array];
for (NSDictionary *issue in self.issues) {
NSString *reference = [issue[@"reference"] ?: @"" uppercaseString];
NSString *location = [issue[@"location_name"] ?: @"" uppercaseString];
NSString *remarks = [issue[@"remarks"] ?: @"" uppercaseString];
NSString *createdAt = [issue[@"created_at"] ?: @"" uppercaseString];
NSString *category = [issue[@"category"] ?: @"" uppercaseString];
NSString *type = [issue[@"type"] ?: @"" uppercaseString];
NSString *issueText = [issue[@"issue"] ?: @"" uppercaseString];
NSString *status = [issue[@"status_external"] ?: @"" uppercaseString];
if ([reference containsString:search] ||
[location containsString:search] ||
[remarks containsString:search] ||
[createdAt containsString:search] ||
[category containsString:search] ||
[type containsString:search] ||
[issueText containsString:search] ||
[status containsString:search]) {
[matches addObject:issue];
}
}
self.filteredIssues = matches;
}
[self.tableView reloadData];
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
[searchBar resignFirstResponder];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
// Clear search text
searchBar.text = @"";
// Reset filtered issues
self.filteredIssues = self.issues;
[self.tableView reloadData];
// Dismiss keyboard
[searchBar resignFirstResponder];
}
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
[searchBar setShowsCancelButton:YES animated:YES];
}
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar {
[searchBar setShowsCancelButton:NO animated:YES];
} }
@end @end
...@@ -25,12 +25,18 @@ ...@@ -25,12 +25,18 @@
self.issueID, self.planID, self.status, self.unitName, self.reference, self.titleText); self.issueID, self.planID, self.status, self.unitName, self.reference, self.titleText);
[self setupHeader]; [self setupHeader];
if (self.isMultiWithdraw){
}
[self setupContent]; [self setupContent];
} }
#pragma mark - Header #pragma mark - Header
- (void)setupHeader { - (void)setupHeader {
self.headerView = [[UIView alloc] init]; CGFloat statusBarHeight = UIApplication.sharedApplication.statusBarFrame.size.height;
self.headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, statusBarHeight + 60)];
self.headerView.translatesAutoresizingMaskIntoConstraints = NO; self.headerView.translatesAutoresizingMaskIntoConstraints = NO;
self.headerView.backgroundColor = [UIColor colorWithRed:0/255.0 green:109/255.0 blue:141/255.0 alpha:1]; self.headerView.backgroundColor = [UIColor colorWithRed:0/255.0 green:109/255.0 blue:141/255.0 alpha:1];
[self.view addSubview:self.headerView]; [self.view addSubview:self.headerView];
...@@ -80,16 +86,32 @@ ...@@ -80,16 +86,32 @@
promptLabel.translatesAutoresizingMaskIntoConstraints = NO; promptLabel.translatesAutoresizingMaskIntoConstraints = NO;
promptLabel.text = @"Write your message:"; promptLabel.text = @"Write your message:";
promptLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightMedium]; promptLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightMedium];
promptLabel.textColor = [UIColor darkGrayColor];
[self.view addSubview:promptLabel]; [self.view addSubview:promptLabel];
self.messageInput = [[UITextView alloc] init]; self.messageInput = [[UITextView alloc] init];
self.messageInput.translatesAutoresizingMaskIntoConstraints = NO; self.messageInput.translatesAutoresizingMaskIntoConstraints = NO;
self.messageInput.font = [UIFont systemFontOfSize:16]; self.messageInput.font = [UIFont systemFontOfSize:16];
// --- Styling ---
self.messageInput.backgroundColor = [UIColor colorWithWhite:0.97 alpha:1.0]; // soft light gray
self.messageInput.textColor = [UIColor blackColor];
self.messageInput.layer.borderWidth = 1.0; self.messageInput.layer.borderWidth = 1.0;
self.messageInput.layer.borderColor = [UIColor lightGrayColor].CGColor; self.messageInput.layer.borderColor = [UIColor colorWithWhite:0.85 alpha:1.0].CGColor;
self.messageInput.layer.cornerRadius = 8; self.messageInput.layer.cornerRadius = 8;
self.messageInput.layer.masksToBounds = YES;
[self.view addSubview:self.messageInput]; [self.view addSubview:self.messageInput];
// --- CREATE confirmButton BEFORE using it in constraints ---
self.confirmButton = [UIButton buttonWithType:UIButtonTypeSystem];
self.confirmButton.translatesAutoresizingMaskIntoConstraints = NO;
[self.confirmButton setTitle:@"Submit" forState:UIControlStateNormal];
self.confirmButton.backgroundColor = [UIColor colorWithRed:0/255.0 green:109/255.0 blue:141/255.0 alpha:1];
[self.confirmButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
self.confirmButton.layer.cornerRadius = 8;
[self.confirmButton addTarget:self action:@selector(handleConfirm) forControlEvents:UIControlEventTouchUpInside];
// don't addSubview yet if you prefer, we'll add below before constraints
UIView *separator = [[UIView alloc] init]; UIView *separator = [[UIView alloc] init];
separator.translatesAutoresizingMaskIntoConstraints = NO; separator.translatesAutoresizingMaskIntoConstraints = NO;
separator.backgroundColor = [UIColor colorWithWhite:0.8 alpha:1]; separator.backgroundColor = [UIColor colorWithWhite:0.8 alpha:1];
...@@ -114,24 +136,46 @@ ...@@ -114,24 +136,46 @@
// ✅ If multiple issues selected — show a list below comment box // ✅ If multiple issues selected — show a list below comment box
if (self.isMultiWithdraw) { if (self.isMultiWithdraw) {
UILabel *listLabel = [[UILabel alloc] init]; // "Withdrawing" title
listLabel.translatesAutoresizingMaskIntoConstraints = NO; UILabel *withdrawingLabel = [[UILabel alloc] init];
listLabel.text = @"Selected Issues"; withdrawingLabel.translatesAutoresizingMaskIntoConstraints = NO;
listLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightSemibold]; withdrawingLabel.text = @"Withdrawing";
[self.view addSubview:listLabel]; withdrawingLabel.font = [UIFont boldSystemFontOfSize:16];
withdrawingLabel.textColor = [UIColor blackColor]; // main title dark
withdrawingLabel.backgroundColor = [UIColor clearColor];
[self.view addSubview:withdrawingLabel];
// "X Issue(s)" label
NSString *countText = [NSString stringWithFormat:@"%lu Issue(s)", (unsigned long)self.selectedIssues.count];
UILabel *countLabel = [[UILabel alloc] init];
countLabel.translatesAutoresizingMaskIntoConstraints = NO;
countLabel.text = countText;
countLabel.font = [UIFont systemFontOfSize:14];
countLabel.textColor = [UIColor colorWithWhite:0.4 alpha:1.0]; // subtle gray text
[self.view addSubview:countLabel];
// Table showing list of issues
self.issuesTable = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleInsetGrouped]; self.issuesTable = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleInsetGrouped];
self.issuesTable.translatesAutoresizingMaskIntoConstraints = NO; self.issuesTable.translatesAutoresizingMaskIntoConstraints = NO;
self.issuesTable.dataSource = self; self.issuesTable.dataSource = self;
self.issuesTable.delegate = self; self.issuesTable.delegate = self;
self.issuesTable.layer.cornerRadius = 8;
self.issuesTable.layer.masksToBounds = YES;
self.issuesTable.layer.borderColor = [UIColor colorWithWhite:0.9 alpha:1.0].CGColor;
self.issuesTable.layer.borderWidth = 1.0;
[self.issuesTable registerClass:[UITableViewCell class] forCellReuseIdentifier:@"WithdrawListCell"];
[self.view addSubview:self.issuesTable]; [self.view addSubview:self.issuesTable];
[constraints addObjectsFromArray:@[ [constraints addObjectsFromArray:@[
[listLabel.topAnchor constraintEqualToAnchor:separator.bottomAnchor constant:20], [withdrawingLabel.topAnchor constraintEqualToAnchor:separator.bottomAnchor constant:20],
[listLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20], [withdrawingLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20],
[self.issuesTable.topAnchor constraintEqualToAnchor:listLabel.bottomAnchor constant:8],
[self.issuesTable.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], [countLabel.topAnchor constraintEqualToAnchor:withdrawingLabel.bottomAnchor constant:4],
[self.issuesTable.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], [countLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20],
[self.issuesTable.topAnchor constraintEqualToAnchor:countLabel.bottomAnchor constant:8],
[self.issuesTable.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20],
[self.issuesTable.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-20],
[self.issuesTable.heightAnchor constraintEqualToConstant:200], [self.issuesTable.heightAnchor constraintEqualToConstant:200],
]]; ]];
...@@ -146,7 +190,9 @@ ...@@ -146,7 +190,9 @@
]]; ]];
} }
// Add confirm button to view so its anchors are valid
[self.view addSubview:self.confirmButton]; [self.view addSubview:self.confirmButton];
[constraints addObjectsFromArray:@[ [constraints addObjectsFromArray:@[
[self.confirmButton.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:40], [self.confirmButton.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:40],
[self.confirmButton.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-40], [self.confirmButton.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-40],
...@@ -157,7 +203,6 @@ ...@@ -157,7 +203,6 @@
[NSLayoutConstraint activateConstraints:constraints]; [NSLayoutConstraint activateConstraints:constraints];
} }
#pragma mark - Actions #pragma mark - Actions
- (void)handleBack { - (void)handleBack {
[self dismissViewControllerAnimated:YES completion:nil]; [self dismissViewControllerAnimated:YES completion:nil];
...@@ -169,42 +214,48 @@ ...@@ -169,42 +214,48 @@
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Alert" UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Alert"
message:@"Please enter a message before submitting." message:@"Please enter a message before submitting."
preferredStyle:UIAlertControllerStyleAlert]; preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"OK" [alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
style:UIAlertActionStyleDefault
handler:nil]];
[self presentViewController:alert animated:YES completion:nil]; [self presentViewController:alert animated:YES completion:nil];
return; return;
} }
// Confirmation dialog before sending
UIAlertController *confirm = [UIAlertController alertControllerWithTitle:@"Confirm" UIAlertController *confirm = [UIAlertController alertControllerWithTitle:@"Confirm"
message:@"Are you sure you want to submit?" message:@"Are you sure you want to submit?"
preferredStyle:UIAlertControllerStyleAlert]; preferredStyle:UIAlertControllerStyleAlert];
[confirm addAction:[UIAlertAction actionWithTitle:@"No" style:UIAlertActionStyleCancel handler:nil]]; [confirm addAction:[UIAlertAction actionWithTitle:@"No" style:UIAlertActionStyleCancel handler:nil]];
[confirm addAction:[UIAlertAction actionWithTitle:@"Yes" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { [confirm addAction:[UIAlertAction actionWithTitle:@"Yes" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
if (self.isMultiWithdraw) { if (self.isMultiWithdraw) {
// Multi-withdraw // Extract only IDs (and skip nils)
NSMutableArray *ids = [NSMutableArray array]; NSMutableArray *ids = [NSMutableArray array];
for (NSDictionary *issue in self.selectedIssues) { for (NSDictionary *issue in self.selectedIssues ?: @[]) {
if (issue[@"id"]) [ids addObject:issue[@"id"]]; id issueId = issue[@"id"];
if (issueId) [ids addObject:issueId];
} }
[IssueAPIClient fetchVoidIssue:ids NSLog(@"📦 Extracted IDs for API: %@", ids);
remarks:message
completion:^(NSDictionary *data, NSError *error) { if (ids.count == 0) {
[self handleVoidIssueResponse:data error:error]; [self showAlertWithTitle:@"Alert" message:@"No valid issue IDs to submit."];
}]; return;
}
[self requestVoidIssue:ids remarks:message];
} }
else if ([self.titleText containsString:@"Delete"]) { else if ([self.titleText containsString:@"Delete"]) {
if (self.issueID == nil) {
[self showAlertWithTitle:@"Alert" message:@"No issue selected to delete."];
return;
}
[self requestDeleteIssue:self.issueID remarks:message]; [self requestDeleteIssue:self.issueID remarks:message];
} }
else { else {
NSArray *singleIssueArray = @[ self.issueID ?: @"" ]; if (self.issueID == nil) {
[IssueAPIClient fetchVoidIssue:singleIssueArray [self showAlertWithTitle:@"Alert" message:@"No issue selected to void."];
remarks:message return;
completion:^(NSDictionary *data, NSError *error) { }
[self handleVoidIssueResponse:data error:error]; NSArray *singleIssueArray = @[ self.issueID ];
}]; [self requestVoidIssue:singleIssueArray remarks:message];
} }
}]]; }]];
[self presentViewController:confirm animated:YES completion:nil]; [self presentViewController:confirm animated:YES completion:nil];
...@@ -247,33 +298,28 @@ ...@@ -247,33 +298,28 @@
}]; }];
} }
# pragma mark - helper -(void)requestVoidIssue:(NSArray *)ids remarks:(NSString *)remarks {
- (void)showAlertWithTitle:(NSString *)title message:(NSString *)message { NSLog(@"🚀 Sending VOID ISSUE for ID=%@, remarks=%@", self.selectedIssues, remarks);
UIAlertController *alert = [UIAlertController alertControllerWithTitle:title
message:message
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil];
[alert addAction:ok];
[self presentViewController:alert animated:YES completion:nil];
}
- (void)handleVoidIssueResponse:(NSDictionary *)data error:(NSError *)error { [IssueAPIClient fetchVoidIssue:ids
remarks:remarks
completion:^(NSDictionary *data, NSError *error) {
if (error) { if (error) {
NSLog(@"❌ Void Issue Error: %@", error.localizedDescription); NSLog(@"Error %@", error.localizedDescription);
[self showAlertWithTitle:@"Error" message:error.localizedDescription];
return; return;
} }
NSDictionary *appData = data[@"AppData"]; NSDictionary *appData = data[@"AppData"];
if ([appData[@"status"] isEqualToString:@"success"]) { if ([appData[@"status"] isEqualToString:@"success"]) {
NSLog(@"✅ Issues voided successfully!"); NSLog(@"✅ Issue voided successfully!");
UIAlertController *successAlert = [UIAlertController alertControllerWithTitle:@"Success" UIAlertController *successAlert = [UIAlertController alertControllerWithTitle:@"Success"
message:@"Issues withdrawn successfully." message:@"Issue voided successfully."
preferredStyle:UIAlertControllerStyleAlert]; preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK" UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK"
style:UIAlertActionStyleDefault style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) { handler:^(UIAlertAction * _Nonnull action) {
// 🏠 Return to dashboard or issue list // 🏠 Mimic AddIssue success dismissal logic
UIViewController *presenter = self.presentingViewController; UIViewController *presenter = self.presentingViewController;
if (presenter.presentingViewController) { if (presenter.presentingViewController) {
[presenter.presentingViewController dismissViewControllerAnimated:YES completion:nil]; [presenter.presentingViewController dismissViewControllerAnimated:YES completion:nil];
...@@ -284,15 +330,27 @@ ...@@ -284,15 +330,27 @@
[successAlert addAction:ok]; [successAlert addAction:ok];
[self presentViewController:successAlert animated:YES completion:nil]; [self presentViewController:successAlert animated:YES completion:nil];
} else { } else {
NSString *message = appData[@"message"] ?: @"Unknown error occurred."; NSString *message = appData[@"message"] ?: @"Unknown error";
NSLog(@"⚠️ Void Issue failed: %@", message); NSLog(@"⚠️ Error Message %@", message);
[self showAlertWithTitle:@"Failed" message:message]; [self showAlertWithTitle:@"Void Failed" message:message];
} }
}];
}
# pragma mark - helper
- (void)showAlertWithTitle:(NSString *)title message:(NSString *)message {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:title
message:message
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil];
[alert addAction:ok];
[self presentViewController:alert animated:YES completion:nil];
} }
#pragma mark - UITableView #pragma mark - UITableView
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.selectedIssues.count; return (NSInteger)(self.selectedIssues ? self.selectedIssues.count : 0);
} }
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
...@@ -302,16 +360,38 @@ ...@@ -302,16 +360,38 @@
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellId]; cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellId];
} }
if (indexPath.row < self.selectedIssues.count) {
NSDictionary *issue = self.selectedIssues[indexPath.row]; NSDictionary *issue = self.selectedIssues[indexPath.row];
cell.textLabel.text = issue[@"reference"] ?: @"(No Ref)"; cell.textLabel.text = issue[@"reference"] ?: @"(No Ref)";
NSString *loc = issue[@"location_name"] ?: @""; NSString *loc = issue[@"location_name"] ?: @"";
NSString *cat = issue[@"category"] ?: @""; NSString *cat = issue[@"category"] ?: @"";
NSString *typ = issue[@"type"] ?: @""; NSString *typ = issue[@"type"] ?: @"";
cell.detailTextLabel.text = [NSString stringWithFormat:@"%@ → %@ → %@", loc, cat, typ]; cell.detailTextLabel.text = [NSString stringWithFormat:@"%@ → %@ → %@", loc, cat, typ];
cell.selectionStyle = UITableViewCellSelectionStyleNone; } else {
cell.textLabel.text = @"(No Ref)";
cell.detailTextLabel.text = @"";
}
cell.backgroundColor = [UIColor whiteColor];
cell.textLabel.textColor = [UIColor blackColor];
cell.detailTextLabel.textColor = [UIColor colorWithWhite:0.4 alpha:1.0];
cell.contentView.backgroundColor = [UIColor colorWithWhite:0.98 alpha:1.0];
cell.layer.cornerRadius = 8;
cell.layer.masksToBounds = NO;
cell.layer.shadowColor = [UIColor colorWithWhite:0 alpha:0.1].CGColor;
cell.layer.shadowOffset = CGSizeMake(0, 2);
cell.layer.shadowOpacity = 0.3;
cell.layer.shadowRadius = 4;
cell.layer.borderWidth = 0.5;
cell.layer.borderColor = [UIColor colorWithWhite:0.9 alpha:1.0].CGColor;
cell.textLabel.font = [UIFont boldSystemFontOfSize:15];
cell.detailTextLabel.font = [UIFont systemFontOfSize:13];
cell.textLabel.textColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0];
cell.detailTextLabel.textColor = [UIColor darkGrayColor];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell; return cell;
} }
@end @end
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<dict> <dict>
<key>Assets.car</key> <key>Assets.car</key>
<data> <data>
KnMHH8GU4NZESWbs6/0uU5WX8uA= EqtjfGVJUrKupCnFW6lfffSo2ZA=
</data> </data>
<key>Headers/QmsPlugin.h</key> <key>Headers/QmsPlugin.h</key>
<data> <data>
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
</data> </data>
<key>Info.plist</key> <key>Info.plist</key>
<data> <data>
ScoY0XAgmZ3U9Q0BvlfgQfJm2bo= w8N5kkR8hr/wIwb/x0XA5+wVpdo=
</data> </data>
<key>Modules/module.modulemap</key> <key>Modules/module.modulemap</key>
<data> <data>
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
<dict> <dict>
<key>hash2</key> <key>hash2</key>
<data> <data>
aLAhYopvL1Lb4CTMG5A8x8RAmnkpXwHQbjsJdpq8gYg= k78SvGog/XWiM8sEWRQ8ZyFHnocCgVMjS4SisBwChjI=
</data> </data>
</dict> </dict>
<key>Headers/QmsPlugin.h</key> <key>Headers/QmsPlugin.h</key>
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<dict> <dict>
<key>Assets.car</key> <key>Assets.car</key>
<data> <data>
KnMHH8GU4NZESWbs6/0uU5WX8uA= EqtjfGVJUrKupCnFW6lfffSo2ZA=
</data> </data>
<key>Headers/QmsPlugin.h</key> <key>Headers/QmsPlugin.h</key>
<data> <data>
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
</data> </data>
<key>Info.plist</key> <key>Info.plist</key>
<data> <data>
JGviPenfphujtQEGyJZCIZTsd2c= uEkE+l7bQzwu7vnX83uBlOCEpCk=
</data> </data>
<key>Modules/module.modulemap</key> <key>Modules/module.modulemap</key>
<data> <data>
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
<dict> <dict>
<key>hash2</key> <key>hash2</key>
<data> <data>
aLAhYopvL1Lb4CTMG5A8x8RAmnkpXwHQbjsJdpq8gYg= k78SvGog/XWiM8sEWRQ8ZyFHnocCgVMjS4SisBwChjI=
</data> </data>
</dict> </dict>
<key>Headers/QmsPlugin.h</key> <key>Headers/QmsPlugin.h</key>
......
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