Commit 9a381188 authored by Wei Han's avatar Wei Han

code update

parent c8fb728f
......@@ -120,8 +120,6 @@
2F9647672E86307D002CC7CB /* QmsPluginFramework */,
);
name = QmsPluginFramework;
packageProductDependencies = (
);
productName = QmsPluginFramework;
productReference = 2F9647652E86307D002CC7CB /* QmsPluginFramework.framework */;
productType = "com.apple.product-type.framework";
......
......@@ -2,8 +2,11 @@
#import "DashboardViewController.h"
#import "DashboardHeaderView.h"
#import <CoreGraphics/CoreGraphics.h>
#import <objc/runtime.h>
#import "PlanViewController.h"
#import "DashboardAPIClient.h"
#import "IssueDetailViewController.h"
#import "IssuesViewController.h"
@interface DashboardViewController ()
......@@ -345,7 +348,6 @@
- (void)handleInspectionBannerTap {
NSLog(@"🟥 Inspection checklist banner tapped");
// In future: open WebView screen or perform navigation
[UIView animateWithDuration:0.1 animations:^{
_inspectionBanner.alpha = 0.6;
} completion:^(BOOL finished) {
......@@ -616,7 +618,7 @@
title.textColor = [UIColor blackColor];
title.userInteractionEnabled = YES; // 👈 enable taps
UITapGestureRecognizer *titleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(sectionHeaderTapped:)];
UITapGestureRecognizer *titleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(issueHeaderTapped:)];
[title addGestureRecognizer:titleTap];
UIImageView *arrow = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"icon_green_arrowright"]];
arrow.frame = CGRectMake(self.view.bounds.size.width - 40, 2, 24, 24);
......@@ -846,6 +848,13 @@
infoLabel.attributedText = [self notificationTextForIssue:item];
[card addSubview:infoLabel];
// Keep a reference to its issue data
card.accessibilityValue = item[@"issue_reference"]; // for debugging
card.tag = self.issues.count; // optional index tagging
// Store the data for later use (simplest way)
objc_setAssociatedObject(card, "issueData", item, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
// === Tap gesture ===
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleIssueTap:)];
......@@ -972,10 +981,19 @@
}
- (void)handleIssueTap:(UITapGestureRecognizer *)gesture {
UIView *card = gesture.view;
[self animateTapForView:card];
NSLog(@"🪲 Issue card tapped");
// TODO: open IssueDetails later
UIView *tappedCard = gesture.view;
NSDictionary *issueData = objc_getAssociatedObject(tappedCard, "issueData");
if (issueData && [issueData isKindOfClass:[NSDictionary class]]) {
NSLog(@"🧭 Navigating to IssueDetailViewController with issue: %@", issueData);
IssueDetailViewController *nextVC = [[IssueDetailViewController alloc] init];
nextVC.modalPresentationStyle = UIModalPresentationFullScreen;
nextVC.issueData = issueData;
[self presentViewController:nextVC animated:YES completion:nil];
} else {
NSLog(@"⚠️ No valid issue data found for tapped card: %@", issueData);
}
}
- (UIImage *)downloadImageFrom:(NSString *)urlString {
......@@ -1013,6 +1031,13 @@
NSLog(@"📘 Section tapped: %@", header.text);
}
-(void)issueHeaderTapped:(UITapGestureRecognizer *)gesture {
IssuesViewController *nextVC = [[IssuesViewController alloc] init];
nextVC.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:nextVC animated:YES completion:nil];
}
- (void)cardTapped:(UITapGestureRecognizer *)gesture {
UIView *card = gesture.view;
[self animateTapForView:card];
......
// IssueAPIClient.h
#import <Foundation/Foundation.h>
@interface IssueAPIClient : NSObject
+ (void)fetchIssues:(void (^)(NSDictionary *data, NSError *error))completion;
@end
// IssueAPIClient.mm
#import "IssueAPIClient.h"
@implementation IssueAPIClient
+ (void)fetchIssues:(void (^)(NSDictionary *data, NSError *error))completion {
// ✅ URL
NSString *urlString = @"https://kitadev.commudesk.com/api/owner/issue/getIssue?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6ImF0aGlyYWh6YWlkaUBjb252ZXAuY29tIiwicGFzc3dvcmQiOiIkMnkkMTAkNU9xYklqMnZ6UHJwckJrcVd5c3I2LmJCc1hVYS9Hd014eUhnL3RhUUhPUkNQcGdmTG8yakciLCJzdWIiOjIxNzAsImlzcyI6Imh0dHBzOi8va2l0YWRldi5jb21tdWRlc2suY29tL2FwaS9vd25lci9hdXRoL3Bhc3N3b3JkbGVzc19sb2dpbiIsImlhdCI6MTc2MDMxNTM1MiwiZXhwIjoyMDc1ODg0ODcyLCJuYmYiOjE3NjAzMTUzNTIsImp0aSI6IktoQmNyQnJEdDVNdDZlWmMifQ.JnxGbZ7hTeoOr6oibIzZMphgyKtTo2Aq9Efx6mrGfFA";
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
// ✅ JSON headers
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
// ✅ Build JSON body
NSDictionary *deviceInfo = @{
@"OS": @"AND",
@"IMEI": @"AND:2a2f13ff17b1cbb5",
@"OS_VERSION": @"35",
@"MODEL": @"2306EPN60G",
@"APP_VERSION": @"1.22.26"
};
NSDictionary *jsonBody = @{
@"data": @{
@"os": @"AND",
@"drawing_plan_id": @"135",
@"information": deviceInfo
}
};
// ✅ Convert dictionary → NSData
NSError *jsonError;
NSData *bodyData = [NSJSONSerialization dataWithJSONObject:jsonBody options:0 error:&jsonError];
if (jsonError) {
NSLog(@"❌ JSON Serialization Error: %@", jsonError);
if (completion) completion(nil, jsonError);
return;
}
request.HTTPBody = bodyData;
// 🧭 Debug logs
NSLog(@"🌍 URL: %@", urlString);
NSLog(@"📦 Body JSON: %@", jsonBody);
// ✅ Make request
NSURLSessionDataTask *task = [[NSURLSession sharedSession]
dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"❌ Network Error: %@", error);
dispatch_async(dispatch_get_main_queue(), ^{
if (completion) completion(nil, error);
});
return;
}
NSError *jsonParseError;
NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonParseError];
if (jsonParseError) {
NSLog(@"⚠️ JSON Parse Error: %@", jsonParseError);
} else {
NSLog(@"✅ Issues API Response:\n%@", jsonResponse);
}
dispatch_async(dispatch_get_main_queue(), ^{
if (completion) completion(jsonResponse, jsonParseError);
});
}];
[task resume];
}
@end
// IssueDetailViewController.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface IssueDetailViewController : UIViewController
@property (nonatomic, strong) NSDictionary *issueData;
@end
NS_ASSUME_NONNULL_END
#import "IssueDetailViewController.h"
@interface IssueDetailViewController ()
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UIView *contentView;
@property (nonatomic, strong) UIImageView *issueImageView;
@property (nonatomic, strong) UILabel *refLabel;
@property (nonatomic, strong) UILabel *statusLabel;
@property (nonatomic, strong) UIView *detailsCard;
@property (nonatomic, strong) UIButton *editButton;
@property (nonatomic, strong) UIButton *deleteButton;
@end
@implementation IssueDetailViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor systemGray6Color];
self.title = @"Issue Details";
NSLog(@"📦 Received Issue Data: %@", self.issueData);
[self setupHeader];
[self setupScrollView];
[self setupHeaderImage];
[self setupDetailsCard];
[self setupButtons];
[self populateData];
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
UIView *headerView = [self.view viewWithTag:999];
if (!headerView) return;
// ✅ Use updated safe area now that it’s available
UILayoutGuide *safe = self.view.safeAreaLayoutGuide;
CGFloat topInset = safe.layoutFrame.origin.y;
CGFloat headerHeight = 56.0 + topInset;
headerView.frame = CGRectMake(0, 0, self.view.bounds.size.width, headerHeight);
// ✅ Adjust subviews within header
UIButton *backButton = [headerView viewWithTag:1];
UILabel *titleLabel = [headerView viewWithTag:2];
UIButton *historyButton = [headerView viewWithTag:3];
backButton.frame = CGRectMake(12, topInset + 8, 44, 40);
titleLabel.frame = CGRectMake(0, topInset + 8, self.view.bounds.size.width, 40);
historyButton.frame = CGRectMake(self.view.bounds.size.width - 56, topInset + 8, 44, 40);
// ✅ Shift scroll view below header
CGFloat headerBottom = CGRectGetMaxY(headerView.frame);
self.scrollView.frame = CGRectMake(0, headerBottom, self.view.bounds.size.width, self.view.bounds.size.height - headerBottom);
}
#pragma mark - Header Setup
- (void)setupHeader {
UIView *headerView = [[UIView alloc] init];
headerView.backgroundColor = [UIColor colorWithRed:0/255.0
green:109/255.0
blue:141/255.0
alpha:1.0];
headerView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
headerView.tag = 999;
[self.view addSubview:headerView];
// --- Back Button ---
UIButton *backButton = [UIButton buttonWithType:UIButtonTypeSystem];
backButton.tag = 1;
[backButton setImage:[UIImage systemImageNamed:@"chevron.left"] forState:UIControlStateNormal];
backButton.tintColor = UIColor.whiteColor;
[backButton addTarget:self action:@selector(handleBackTap) forControlEvents:UIControlEventTouchUpInside];
[headerView addSubview:backButton];
// --- Title ---
UILabel *titleLabel = [[UILabel alloc] init];
titleLabel.tag = 2;
titleLabel.text = @"Issue Details";
titleLabel.font = [UIFont boldSystemFontOfSize:18];
titleLabel.textAlignment = NSTextAlignmentCenter;
titleLabel.textColor = UIColor.whiteColor;
[headerView addSubview:titleLabel];
// --- History Button ---
UIButton *historyButton = [UIButton buttonWithType:UIButtonTypeSystem];
historyButton.tag = 3;
[historyButton setImage:[UIImage systemImageNamed:@"clock.arrow.circlepath"] forState:UIControlStateNormal];
historyButton.tintColor = UIColor.whiteColor;
[historyButton addTarget:self action:@selector(handleHistoryTap) forControlEvents:UIControlEventTouchUpInside];
[headerView addSubview:historyButton];
}
#pragma mark - UI Setup
- (void)setupScrollView {
UIView *headerView = [self.view viewWithTag:999];
CGFloat headerBottom = CGRectGetMaxY(headerView.frame);
self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, headerBottom, self.view.bounds.size.width, self.view.bounds.size.height - headerBottom)];
self.scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.scrollView.backgroundColor = [UIColor whiteColor];
[self.view addSubview:self.scrollView];
}
- (void)setupHeaderImage {
CGFloat imageHeight = 230;
self.issueImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, imageHeight)];
self.issueImageView.contentMode = UIViewContentModeScaleAspectFill;
self.issueImageView.clipsToBounds = YES;
self.issueImageView.backgroundColor = [UIColor colorWithWhite:0.9 alpha:1];
[self.scrollView addSubview:self.issueImageView];
}
- (void)setupDetailsCard {
CGFloat topOffset = 220;
CGFloat padding = 20;
self.detailsCard = [[UIView alloc] initWithFrame:CGRectMake(0, topOffset, self.view.bounds.size.width, 420)];
self.detailsCard.backgroundColor = UIColor.whiteColor;
self.detailsCard.layer.cornerRadius = 20;
self.detailsCard.layer.maskedCorners = kCALayerMinXMinYCorner | kCALayerMaxXMinYCorner;
[self.scrollView addSubview:self.detailsCard];
CGFloat y = 20;
// --- Reference ID ---
self.refLabel = [[UILabel alloc] initWithFrame:CGRectMake(padding, y, self.view.bounds.size.width - 2*padding, 24)];
self.refLabel.font = [UIFont boldSystemFontOfSize:20];
[self.detailsCard addSubview:self.refLabel];
y += 36;
// --- Status Capsule ---
self.statusLabel = [[UILabel alloc] initWithFrame:CGRectMake(padding, y, 90, 28)];
self.statusLabel.font = [UIFont boldSystemFontOfSize:14];
self.statusLabel.textColor = UIColor.whiteColor;
self.statusLabel.textAlignment = NSTextAlignmentCenter;
self.statusLabel.layer.cornerRadius = 14;
self.statusLabel.layer.masksToBounds = YES;
[self.detailsCard addSubview:self.statusLabel];
y += 50;
// --- Info Labels ---
NSArray *titles = @[@"Created Date", @"Location", @"Category", @"Type", @"Issue", @"Created By", @"Comment"];
for (NSString *title in titles) {
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(padding, y, 120, 22)];
titleLabel.text = [NSString stringWithFormat:@"%@ :", title];
titleLabel.textColor = UIColor.darkGrayColor;
titleLabel.font = [UIFont systemFontOfSize:15];
[self.detailsCard addSubview:titleLabel];
UILabel *valueLabel = [[UILabel alloc] initWithFrame:CGRectMake(padding + 130, y, self.view.bounds.size.width - 150, 22)];
valueLabel.tag = [titles indexOfObject:title] + 100; // tag for later update
valueLabel.textColor = UIColor.blackColor;
valueLabel.font = [UIFont systemFontOfSize:15 weight:UIFontWeightMedium];
[self.detailsCard addSubview:valueLabel];
y += 28;
}
}
- (void)setupButtons {
CGFloat y = CGRectGetMaxY(self.detailsCard.frame) + 16;
CGFloat buttonWidth = (self.view.bounds.size.width - 60) / 2;
// --- Edit Button ---
self.editButton = [UIButton buttonWithType:UIButtonTypeSystem];
self.editButton.frame = CGRectMake(20, y, buttonWidth, 44);
[self.editButton setTitle:@"Edit Issue" forState:UIControlStateNormal];
[self.editButton setTitleColor:[UIColor colorWithRed:0/255.0 green:115/255.0 blue:130/255.0 alpha:1] forState:UIControlStateNormal];
self.editButton.layer.cornerRadius = 8;
self.editButton.layer.borderWidth = 1;
self.editButton.layer.borderColor = [UIColor colorWithRed:0/255.0 green:115/255.0 blue:130/255.0 alpha:1].CGColor;
[self.scrollView addSubview:self.editButton];
// --- Delete Button ---
self.deleteButton = [UIButton buttonWithType:UIButtonTypeSystem];
self.deleteButton.frame = CGRectMake(CGRectGetMaxX(self.editButton.frame) + 20, y, buttonWidth, 44);
[self.deleteButton setTitle:@"Delete Issue" forState:UIControlStateNormal];
[self.deleteButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
self.deleteButton.backgroundColor = [UIColor systemRedColor];
self.deleteButton.layer.cornerRadius = 8;
[self.scrollView addSubview:self.deleteButton];
CGFloat totalHeight = CGRectGetMaxY(self.deleteButton.frame) + 30;
self.scrollView.contentSize = CGSizeMake(self.view.bounds.size.width, totalHeight);
}
#pragma mark - Data
- (void)populateData {
if (!self.issueData) return;
NSString *ref = self.issueData[@"issue_reference"] ?: @"Unknown Reference";
NSString *status = self.issueData[@"status_external"] ?: @"No Status";
NSString *statusColor = self.issueData[@"status_ex_color"] ?: @"#999999";
NSString *imageURL = self.issueData[@"image"];
// it is the correct spelling for self.issueData[@"creted_by"]
NSDictionary *createdBy = self.issueData[@"creted_by"];
NSArray *values = @[
self.issueData[@"created_at"] ?: @"–",
self.issueData[@"location_name"] ?: @"–",
self.issueData[@"category"] ?: @"–",
self.issueData[@"type"] ?: @"–",
self.issueData[@"issue"] ?: @"–",
createdBy[@"name"] ?: @"-",
self.issueData[@"remarks"] ?: @"–"
];
self.refLabel.text = ref;
self.statusLabel.text = status;
self.statusLabel.backgroundColor = [self colorFromHex:statusColor];
// Fill info rows
for (int i = 0; i < values.count; i++) {
UILabel *label = [self.detailsCard viewWithTag:100 + i];
if ([label isKindOfClass:[UILabel class]]) {
label.text = values[i];
}
}
// Load image
if (imageURL.length > 0) {
NSURL *url = [NSURL URLWithString:imageURL];
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.issueImageView.image = img;
});
}
});
}
}
#pragma mark - Helper
- (UIColor *)colorFromHex:(NSString *)hexString {
if (!hexString || hexString.length < 6) return [UIColor grayColor];
unsigned int rgbValue = 0;
NSScanner *scanner = [NSScanner scannerWithString:hexString];
if ([hexString hasPrefix:@"#"]) scanner.scanLocation = 1;
[scanner scanHexInt:&rgbValue];
return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0
green:((rgbValue & 0x00FF00) >> 8)/255.0
blue:(rgbValue & 0x0000FF)/255.0
alpha:1.0];
}
#pragma mark - Button Actions
- (void)handleBackTap {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)handleHistoryTap {
NSLog(@"🕓 History tapped");
// TODO: Navigate to issue history screen later
}
@end
// IssuesViewControlller.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface IssuesViewController : UIViewController
@end
NS_ASSUME_NONNULL_END
// IssuesViewController.mm
#import "IssuesViewController.h"
#import "IssueAPIClient.h"
#import "IssueDetailViewController.h"
#pragma mark - Internal IssueCell
@interface IssueCell : 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;
@end
@implementation IssueCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.selectionStyle = UITableViewCellSelectionStyleNone;
self.selectionStyle = UITableViewCellSelectionStyleNone;
self.backgroundColor = UIColor.clearColor;
UIView *card = [[UIView alloc] init];
card.backgroundColor = UIColor.whiteColor;
card.layer.cornerRadius = 12;
card.layer.shadowColor = [UIColor colorWithWhite:0 alpha:0.15].CGColor;
card.layer.shadowOpacity = 0.1;
card.layer.shadowRadius = 3;
card.layer.shadowOffset = CGSizeMake(0, 2);
card.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView addSubview:card];
self.thumbView = [[UIImageView alloc] init];
self.thumbView.layer.cornerRadius = 22;
self.thumbView.clipsToBounds = YES;
self.thumbView.translatesAutoresizingMaskIntoConstraints = NO;
self.thumbView.contentMode = UIViewContentModeScaleAspectFill;
[card addSubview:self.thumbView];
self.referenceLabel = [[UILabel alloc] init];
self.referenceLabel.font = [UIFont boldSystemFontOfSize:15];
self.referenceLabel.textColor = [UIColor colorWithRed:0.0 green:0.45 blue:0.55 alpha:1];
self.referenceLabel.translatesAutoresizingMaskIntoConstraints = NO;
[card addSubview:self.referenceLabel];
self.statusLabel = [[UILabel alloc] init];
self.statusLabel.font = [UIFont systemFontOfSize:13 weight:UIFontWeightSemibold];
self.statusLabel.textColor = UIColor.whiteColor;
self.statusLabel.textAlignment = NSTextAlignmentCenter;
self.statusLabel.backgroundColor = [UIColor systemBlueColor];
self.statusLabel.layer.cornerRadius = 12;
self.statusLabel.clipsToBounds = YES;
self.statusLabel.translatesAutoresizingMaskIntoConstraints = NO;
[card addSubview:self.statusLabel];
self.locationLabel = [[UILabel alloc] init];
self.locationLabel.font = [UIFont boldSystemFontOfSize:16];
self.locationLabel.textColor = UIColor.labelColor;
self.locationLabel.translatesAutoresizingMaskIntoConstraints = NO;
[card addSubview:self.locationLabel];
self.createdLabel = [[UILabel alloc] init];
self.createdLabel.font = [UIFont systemFontOfSize:13];
self.createdLabel.textColor = [UIColor colorWithWhite:0.45 alpha:1];
self.createdLabel.translatesAutoresizingMaskIntoConstraints = NO;
[card addSubview:self.createdLabel];
self.detailsLabel = [[UILabel alloc] init];
self.detailsLabel.font = [UIFont systemFontOfSize:14];
self.detailsLabel.textColor = UIColor.darkGrayColor;
self.detailsLabel.numberOfLines = 2;
self.detailsLabel.translatesAutoresizingMaskIntoConstraints = NO;
[card addSubview:self.detailsLabel];
[NSLayoutConstraint activateConstraints:@[
[card.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:6],
[card.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
[card.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-16],
[card.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor constant:-6],
[self.thumbView.leadingAnchor constraintEqualToAnchor:card.leadingAnchor constant:12],
[self.thumbView.topAnchor constraintEqualToAnchor:card.topAnchor constant:12],
[self.thumbView.widthAnchor constraintEqualToConstant:44],
[self.thumbView.heightAnchor constraintEqualToConstant:44],
[self.statusLabel.trailingAnchor constraintEqualToAnchor:card.trailingAnchor constant:-12],
[self.statusLabel.topAnchor constraintEqualToAnchor:card.topAnchor constant:12],
[self.statusLabel.widthAnchor constraintEqualToConstant:70],
[self.statusLabel.heightAnchor constraintEqualToConstant:24],
[self.locationLabel.leadingAnchor constraintEqualToAnchor:self.thumbView.trailingAnchor constant:12],
[self.locationLabel.topAnchor constraintEqualToAnchor:card.topAnchor constant:12],
[self.createdLabel.leadingAnchor constraintEqualToAnchor:self.thumbView.trailingAnchor constant:12],
[self.createdLabel.topAnchor constraintEqualToAnchor:self.locationLabel.bottomAnchor constant:4],
[self.referenceLabel.leadingAnchor constraintEqualToAnchor:card.leadingAnchor constant:12],
[self.referenceLabel.topAnchor constraintEqualToAnchor:self.thumbView.bottomAnchor constant:8],
[self.detailsLabel.leadingAnchor constraintEqualToAnchor:card.leadingAnchor constant:12],
[self.detailsLabel.trailingAnchor constraintEqualToAnchor:card.trailingAnchor constant:-12],
[self.detailsLabel.topAnchor constraintEqualToAnchor:self.referenceLabel.bottomAnchor constant:4],
[self.detailsLabel.bottomAnchor constraintEqualToAnchor:card.bottomAnchor constant:-12],
]];
}
return self;
}
@end
@interface IssuesViewController () <UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate>
@property (nonatomic, strong) UIView *headerView;
@property (nonatomic, strong) UIButton *backButton;
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UIButton *withdrawButton;
@property (nonatomic, strong) UIButton *poaButton;
@property (nonatomic, strong) UIButton *filterButton;
@property (nonatomic, strong) UILabel *filterLabel;
@property (nonatomic, strong) UISearchBar *searchBar;
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) NSArray *issues;
@property (nonatomic, strong) NSDictionary *issueResponse;
@property (nonatomic, strong) NSString *selectedFilter;
@property (nonatomic, strong) NSArray<NSDictionary *> *groupedIssues;
@property (nonatomic, strong) NSString *searchText;
@property (nonatomic, strong) NSArray *filteredIssues;
@property (nonatomic, strong) NSArray *filteredGroupedIssues;
@end
@implementation IssuesViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor systemGroupedBackgroundColor];
[self setupHeader];
[self setupFilterBar];
[self setupSearchBar];
[self setupTableView];
self.tableView.sectionHeaderTopPadding = 0; // Optional, iOS 15+ removes top gap
self.tableView.sectionHeaderHeight = 34;
self.tableView.estimatedSectionHeaderHeight = 34;
[self setupConstraints];
[self handleGetIssue];
self.selectedFilter = @"All";
}
#pragma mark - Setup UI
- (void)setupHeader {
self.headerView = [[UIView alloc] init];
self.headerView.translatesAutoresizingMaskIntoConstraints = NO;
self.headerView.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0]; // THEME COLOR
[self.view addSubview:self.headerView];
// Back Button
self.backButton = [UIButton buttonWithType:UIButtonTypeSystem];
[self.backButton setImage:[UIImage systemImageNamed:@"chevron.left"] forState:UIControlStateNormal];
self.backButton.tintColor = UIColor.whiteColor;
self.backButton.translatesAutoresizingMaskIntoConstraints = NO;
[self.backButton addTarget:self action:@selector(backTapped) forControlEvents:UIControlEventTouchUpInside];
[self.headerView addSubview:self.backButton];
// Title
self.titleLabel = [[UILabel alloc] init];
self.titleLabel.text = @"Issues";
self.titleLabel.textColor = UIColor.whiteColor;
self.titleLabel.font = [UIFont boldSystemFontOfSize:20];
self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
[self.headerView addSubview:self.titleLabel];
// Withdraw Button
self.withdrawButton = [UIButton buttonWithType:UIButtonTypeSystem];
[self.withdrawButton setImage:[UIImage systemImageNamed:@"tray.and.arrow.down"] forState:UIControlStateNormal];
self.withdrawButton.tintColor = UIColor.whiteColor;
self.withdrawButton.translatesAutoresizingMaskIntoConstraints = NO;
[self.withdrawButton addTarget:self action:@selector(withdrawTapped) forControlEvents:UIControlEventTouchUpInside];
[self.headerView addSubview:self.withdrawButton];
// POA Button
self.poaButton = [UIButton buttonWithType:UIButtonTypeSystem];
[self.poaButton setImage:[UIImage systemImageNamed:@"doc.text"] forState:UIControlStateNormal];
self.poaButton.tintColor = UIColor.whiteColor;
self.poaButton.translatesAutoresizingMaskIntoConstraints = NO;
[self.poaButton addTarget:self action:@selector(poaTapped) forControlEvents:UIControlEventTouchUpInside];
[self.headerView addSubview:self.poaButton];
}
- (void)setupFilterBar {
self.filterButton = [UIButton buttonWithType:UIButtonTypeSystem];
self.filterButton.translatesAutoresizingMaskIntoConstraints = NO;
self.filterButton.layer.cornerRadius = 20;
self.filterButton.layer.borderWidth = 0.5;
self.filterButton.layer.borderColor = [UIColor lightGrayColor].CGColor;
[self.filterButton setTitle:@"Filter: All" forState:UIControlStateNormal];
self.filterButton.tintColor = UIColor.labelColor;
self.filterButton.backgroundColor = UIColor.whiteColor;
self.filterButton.titleLabel.font = [UIFont systemFontOfSize:15];
[self.filterButton addTarget:self action:@selector(filterTapped) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.filterButton];
}
- (void)setupSearchBar {
self.searchBar = [[UISearchBar alloc] init];
self.searchBar.placeholder = @"Search by reference...";
self.searchBar.translatesAutoresizingMaskIntoConstraints = NO;
self.searchBar.delegate = self;
self.searchBar.autocapitalizationType = UITextAutocapitalizationTypeNone;
self.searchBar.autocorrectionType = UITextAutocorrectionTypeNo;
self.searchBar.returnKeyType = UIReturnKeyDone;
[self.view addSubview:self.searchBar];
}
- (void)setupTableView {
self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleInsetGrouped];
self.tableView.translatesAutoresizingMaskIntoConstraints = NO;
self.tableView.delegate = self;
self.tableView.dataSource = self;
[self.tableView registerClass:[IssueCell class] forCellReuseIdentifier:@"IssueCell"];
// 🔹 Section header behavior
if (@available(iOS 15.0, *)) {
self.tableView.sectionHeaderTopPadding = 0;
}
self.tableView.sectionHeaderHeight = 34;
self.tableView.estimatedSectionHeaderHeight = 34;
[self.view addSubview:self.tableView];
}
- (void)setupConstraints {
UILayoutGuide *guide = self.view.safeAreaLayoutGuide;
[NSLayoutConstraint activateConstraints:@[
// Header
[self.headerView.topAnchor constraintEqualToAnchor:guide.topAnchor],
[self.headerView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.headerView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.headerView.heightAnchor constraintEqualToConstant:56],
[self.backButton.leadingAnchor constraintEqualToAnchor:self.headerView.leadingAnchor constant:12],
[self.backButton.centerYAnchor constraintEqualToAnchor:self.headerView.centerYAnchor],
[self.titleLabel.centerXAnchor constraintEqualToAnchor:self.headerView.centerXAnchor],
[self.titleLabel.centerYAnchor constraintEqualToAnchor:self.headerView.centerYAnchor],
[self.withdrawButton.trailingAnchor constraintEqualToAnchor:self.headerView.trailingAnchor constant:-56],
[self.withdrawButton.centerYAnchor constraintEqualToAnchor:self.headerView.centerYAnchor],
[self.poaButton.trailingAnchor constraintEqualToAnchor:self.headerView.trailingAnchor constant:-12],
[self.poaButton.centerYAnchor constraintEqualToAnchor:self.headerView.centerYAnchor],
// Filter
[self.filterButton.topAnchor constraintEqualToAnchor:self.headerView.bottomAnchor constant:12],
[self.filterButton.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:16],
[self.filterButton.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-16],
[self.filterButton.heightAnchor constraintEqualToConstant:40],
// Search
[self.searchBar.topAnchor constraintEqualToAnchor:self.filterButton.bottomAnchor constant:8],
[self.searchBar.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.searchBar.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
// Table
[self.tableView.topAnchor constraintEqualToAnchor:self.searchBar.bottomAnchor constant:8],
[self.tableView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.tableView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.tableView.bottomAnchor constraintEqualToAnchor:guide.bottomAnchor],
]];
}
#pragma mark - Networking
- (void)handleGetIssue {
NSLog(@"🌐 Fetching Issue data...");
[IssueAPIClient fetchIssues:^(NSDictionary *data, NSError *error) {
if (error) {
NSLog(@"❌ Issue fetch failed: %@", error.localizedDescription);
return;
}
NSLog(@"✅ Raw Issue response received");
// Save response to Documents for inspection
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:data options:NSJSONWritingPrettyPrinted error:nil];
NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString *filePath = [docsPath stringByAppendingPathComponent:@"getIssue.txt"];
[jsonData writeToFile:filePath atomically:YES];
NSLog(@"📁 Issue saved to %@", filePath);
// 🔹 Save the full API response
self.issueResponse = data;
// 🔍 Parse JSON
NSDictionary *appData = data[@"AppData"];
if (![appData[@"status"] isEqualToString:@"success"]) {
NSLog(@"⚠️ Server returned non-success status: %@", appData[@"message"]);
return;
}
NSArray *mainData = data[@"Data"];
if (mainData.count == 0) {
NSLog(@"⚠️ No unit plan data found");
return;
}
// 🔹 Sort by date (latest first)
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"dd/MM/yyyy";
NSArray *sorted = [mainData sortedArrayUsingComparator:^NSComparisonResult(NSDictionary *a, NSDictionary *b) {
NSDate *dA = [formatter dateFromString:a[@"created_at"] ?: @""];
NSDate *dB = [formatter dateFromString:b[@"created_at"] ?: @""];
return [dB compare:dA]; // newest → oldest
}];
self.issues = sorted;
// ✅ Reload UI on main thread
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
NSLog(@"✅ Issues loaded: %lu", (unsigned long)self.issues.count);
}];
}
#pragma mark - search bar
- (void)applySearch:(NSString *)searchValue {
if (searchValue.length == 0) {
self.filteredIssues = nil;
self.filteredGroupedIssues = nil;
[self.tableView reloadData];
return;
}
NSString *search = [searchValue uppercaseString];
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];
if ([reference containsString:search] ||
[location containsString:search] ||
[remarks containsString:search]) {
[matches addObject:issue];
}
}
// 🧩 If user is filtering by Status/Location/Date → regroup
if (![self.selectedFilter isEqualToString:@"All"]) {
NSMutableDictionary<NSString *, NSMutableArray *> *map = [NSMutableDictionary dictionary];
for (NSDictionary *issue in matches) {
NSString *key = @"";
if ([self.selectedFilter isEqualToString:@"Status"]) {
key = issue[@"status_external"] ?: @"(No Status)";
} else if ([self.selectedFilter isEqualToString:@"Location"]) {
key = issue[@"location_name"] ?: @"(No Location)";
} else if ([self.selectedFilter isEqualToString:@"Date"]) {
key = issue[@"created_at"] ?: @"(No Date)";
}
if (!map[key]) map[key] = [NSMutableArray array];
[map[key] addObject:issue];
}
NSArray *sortedKeys;
if ([self.selectedFilter isEqualToString:@"Date"]) {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"dd/MM/yyyy";
sortedKeys = [[map allKeys] sortedArrayUsingComparator:^NSComparisonResult(NSString *a, NSString *b) {
NSDate *dA = [formatter dateFromString:a];
NSDate *dB = [formatter dateFromString:b];
return [dB compare:dA]; // newest first
}];
} else {
sortedKeys = [[map allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
}
NSMutableArray *grouped = [NSMutableArray array];
for (NSString *key in sortedKeys) {
[grouped addObject:@{ @"title": key, @"data": map[key] }];
}
self.filteredGroupedIssues = grouped;
self.filteredIssues = nil;
} else {
self.filteredIssues = matches;
self.filteredGroupedIssues = nil;
}
[self.tableView reloadData];
}
#pragma mark - Actions
- (void)backTapped {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)withdrawTapped {
NSLog(@"Withdraw button tapped");
}
- (void)poaTapped {
NSLog(@"POA button tapped");
}
# pragma mark - Filter
- (void)filterTapped {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Filter By"
message:nil
preferredStyle:UIAlertControllerStyleActionSheet];
NSArray *filters = @[@"All", @"Status", @"Location", @"Date"];
for (NSString *filter in filters) {
UIAlertAction *action = [UIAlertAction actionWithTitle:filter
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) {
[self applyFilter:filter];
}];
[alert addAction:action];
}
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
[self presentViewController:alert animated:YES completion:nil];
}
- (void)applyFilter:(NSString *)filter {
self.selectedFilter = filter;
if ([filter isEqualToString:@"All"]) {
self.groupedIssues = @[]; // Flat mode
} else {
NSMutableArray *groups = [NSMutableArray array];
NSMutableDictionary<NSString *, NSMutableArray *> *map = [NSMutableDictionary dictionary];
for (NSDictionary *issue in self.issues) {
NSString *key = @"";
if ([filter isEqualToString:@"Status"]) {
key = issue[@"status_external"] ?: @"(No Status)";
} else if ([filter isEqualToString:@"Location"]) {
key = issue[@"location_name"] ?: @"(No Location)";
} else if ([filter isEqualToString:@"Date"]) {
key = issue[@"created_at"] ?: @"(No Date)";
}
if (!map[key]) {
map[key] = [NSMutableArray array];
}
[map[key] addObject:issue];
}
NSArray *sortedKeys;
if ([filter isEqualToString:@"Date"]) {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"dd/MM/yyyy";
sortedKeys = [[map allKeys] sortedArrayUsingComparator:^NSComparisonResult(NSString *a, NSString *b) {
NSDate *dA = [formatter dateFromString:a];
NSDate *dB = [formatter dateFromString:b];
return [dB compare:dA]; // newest → oldest
}];
} else if ([filter isEqualToString:@"Status"] || [filter isEqualToString:@"Location"]) {
sortedKeys = [[map allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
} else {
sortedKeys = [map allKeys];
}
for (NSString *key in sortedKeys) {
[groups addObject:@{
@"title": key,
@"data": map[key]
}];
}
self.groupedIssues = groups;
}
// 🔹 Update the filter button title dynamically
NSString *buttonTitle = [NSString stringWithFormat:@"Filter: %@", filter];
[self.filterButton setTitle:buttonTitle forState:UIControlStateNormal];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
}
- (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
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// If user is searching:
if (self.filteredIssues || self.filteredGroupedIssues) {
if (self.filteredGroupedIssues) return self.filteredGroupedIssues.count;
return 1;
}
// Otherwise, normal mode
if ([self.selectedFilter isEqualToString:@"All"]) return 1;
return self.groupedIssues.count;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
// Hide default iOS header text (we use a custom header view below)
return nil;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (self.filteredIssues) return self.filteredIssues.count;
if (self.filteredGroupedIssues) {
NSArray *rows = self.filteredGroupedIssues[section][@"data"];
return rows.count;
}
if ([self.selectedFilter isEqualToString:@"All"]) return self.issues.count;
NSArray *rows = self.groupedIssues[section][@"data"];
return rows.count;
}
- (NSDictionary *)issueAtIndexPath:(NSIndexPath *)indexPath {
if (self.filteredIssues) return self.filteredIssues[indexPath.row];
if (self.filteredGroupedIssues) return self.filteredGroupedIssues[indexPath.section][@"data"][indexPath.row];
if ([self.selectedFilter isEqualToString:@"All"]) return self.issues[indexPath.row];
return self.groupedIssues[indexPath.section][@"data"][indexPath.row];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
IssueCell *cell = [tableView dequeueReusableCellWithIdentifier:@"IssueCell" forIndexPath:indexPath];
// --- Reset reused cell state ---
cell.thumbView.image = nil;
for (UIView *subview in cell.thumbView.subviews) {
[subview removeFromSuperview];
}
NSDictionary *issue = [self issueAtIndexPath:indexPath];
NSString *reference = issue[@"reference"] ?: @"";
NSString *location = issue[@"location_name"] ?: @"";
NSString *createdAt = issue[@"created_at"] ?: @"";
NSString *category = issue[@"category"] ?: @"";
NSString *type = issue[@"type"] ?: @"";
NSString *issueText = issue[@"issue"] ?: @"";
NSString *status = issue[@"status_external"] ?: @"";
NSString *statusColor = issue[@"status_ex_color"] ?: @"#CCCCCC";
NSString *thumbURL = issue[@"thumb_image"] ?: @"";
cell.referenceLabel.text = reference;
cell.locationLabel.text = location;
cell.createdLabel.text = [NSString stringWithFormat:@"Created on %@", createdAt];
cell.detailsLabel.text = [NSString stringWithFormat:@"%@ → %@ → %@", category, type, issueText];
cell.statusLabel.text = status;
cell.statusLabel.backgroundColor = [self colorFromHexString:statusColor];
// --- Thumbnail Handling ---
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(), ^{
IssueCell *updateCell = [tableView cellForRowAtIndexPath:indexPath];
if (!updateCell) return;
// Clear any "No image" 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];
}
return cell;
}
#pragma mark - Custom Section Header
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
NSArray *sourceGroups = self.filteredGroupedIssues ?: self.groupedIssues;
if ([self.selectedFilter isEqualToString:@"All"] && !self.filteredGroupedIssues) return nil;
if (section >= sourceGroups.count) return nil;
NSDictionary *group = sourceGroups[section];
NSString *title = group[@"title"] ?: @"";
UIView *headerView = [[UIView alloc] init];
headerView.backgroundColor = [UIColor colorWithWhite:0.94 alpha:1.0];
UILabel *titleLabel = [[UILabel alloc] init];
titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
titleLabel.font = [UIFont boldSystemFontOfSize:17];
titleLabel.textColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0]; // theme color
titleLabel.text = title.uppercaseString;
UIView *underline = [[UIView alloc] init];
underline.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:0.6];
underline.translatesAutoresizingMaskIntoConstraints = NO;
[headerView addSubview:titleLabel];
[headerView addSubview:underline];
[NSLayoutConstraint activateConstraints:@[
[titleLabel.leadingAnchor constraintEqualToAnchor:headerView.leadingAnchor constant:16],
[titleLabel.bottomAnchor constraintEqualToAnchor:headerView.bottomAnchor constant:-6],
[underline.leadingAnchor constraintEqualToAnchor:headerView.leadingAnchor constant:16],
[underline.trailingAnchor constraintEqualToAnchor:headerView.trailingAnchor constant:-16],
[underline.bottomAnchor constraintEqualToAnchor:headerView.bottomAnchor],
[underline.heightAnchor constraintEqualToConstant:1],
]];
return headerView;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
if ([self.selectedFilter isEqualToString:@"All"] && !self.filteredGroupedIssues) return 0;
return 34;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 140;
}
#pragma mark - Helpers
- (void)setNoImagePlaceholder:(UIImageView *)thumbView {
// Clear any previous content
thumbView.image = nil;
thumbView.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1.0];
for (UIView *subview in thumbView.subviews) {
[subview removeFromSuperview];
}
UILabel *noImageLabel = [[UILabel alloc] init];
noImageLabel.text = @"No image";
noImageLabel.textAlignment = NSTextAlignmentCenter;
noImageLabel.font = [UIFont systemFontOfSize:10];
noImageLabel.textColor = [UIColor grayColor];
noImageLabel.translatesAutoresizingMaskIntoConstraints = NO;
[thumbView addSubview:noImageLabel];
[NSLayoutConstraint activateConstraints:@[
[noImageLabel.centerXAnchor constraintEqualToAnchor:thumbView.centerXAnchor],
[noImageLabel.centerYAnchor constraintEqualToAnchor:thumbView.centerYAnchor]
]];
}
#pragma mark - TableView Delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSDictionary *issue;
if ([self.selectedFilter isEqualToString:@"All"]) {
issue = self.issues[indexPath.row];
} else {
issue = self.groupedIssues[indexPath.section][@"data"][indexPath.row];
}
IssueDetailViewController *detailVC = [[IssueDetailViewController alloc] init];
detailVC.modalPresentationStyle = UIModalPresentationFullScreen;
detailVC.issueData = issue; // Pass the selected data
NSLog(@"🧭 Navigating to IssueDetailsViewController with issue: %@", issue);
[self presentViewController:detailVC animated:YES completion:nil];
}
@end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment