Commit e71683b7 authored by Wei Han's avatar Wei Han

code update

parent 61c8d727
......@@ -8,6 +8,16 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, strong) NSString *projectCode;
@property (nonatomic, strong) NSString *projectName;
@property (nonatomic, strong) NSString *type;
@property (nonatomic, strong) NSString *unitID;
@property (nonatomic, strong) NSString *unitName;
@property (nonatomic, strong) NSString *action;
@property (nonatomic, assign) BOOL offline;
@property (nonatomic, strong) NSString *locationName;
@property (nonatomic, strong) NSString *locationId;
@property (nonatomic, strong) NSDictionary *issueContent;
@property (nonatomic, strong) NSDictionary *issueFullData;
@end
NS_ASSUME_NONNULL_END
......@@ -43,7 +43,8 @@
[super viewDidLoad];
self.view.backgroundColor = UIColor.whiteColor;
NSLog(@"PlanViewController loaded");
NSLog(@"🧭 Navigated to PlanScreen with:\n type=%@\n unitID=%@\n unitName=%@\n location= %@ & %@\n issue_id=%@\n",
self.type, self.unitID, self.unitName, self.locationName, self.locationId, self.issueContent[@"issue_id"]);
// Create UI elements (but don’t assign final frames yet)
[self createHeader];
[self createScrollView];
......@@ -135,10 +136,71 @@
dispatch_async(dispatch_get_main_queue(), ^{
[self displayPlanImage];
[self debugPrintAllIssues];
// 🧭 Auto-lock logic for edit mode
NSString *action = self.passedData[@"action"];
if ([action isEqualToString:@"edit_issue"]) {
NSLog(@"✏️ Edit mode detected — auto-selecting issue location");
// Option 1️⃣ — If you have coordinates
NSString *posX = [NSString stringWithFormat:@"%@", self.passedData[@"issue_content"][@"pos_x"] ?: @""];
NSString *posY = [NSString stringWithFormat:@"%@", self.passedData[@"issue_content"][@"pos_y"] ?: @""];
if (posX.length > 0 && posY.length > 0) {
self.tappedPlanX = [posX floatValue];
self.tappedPlanY = [posY floatValue];
[self highlightExistingIssueAtCoordinates:self.tappedPlanX Y:self.tappedPlanY];
}
// Option 2️⃣ — If you prefer locking by location name
NSString *locationName = self.passedData[@"location_name"];
if (locationName.length > 0) {
self.selectedLocation = locationName;
[self showAddIssuePopup]; // show popup immediately
}
}
});
}];
}
- (void)highlightExistingIssueAtCoordinates:(CGFloat)x Y:(CGFloat)y {
NSLog(@"📍 Highlighting existing issue at (%.2f, %.2f)", x, y);
if (!self.planImageView.image) {
NSLog(@"⚠️ Plan image not ready yet");
return;
}
CGRect imageRect = [self imageRectInImageView:self.planImageView];
CGFloat displayedWidth = imageRect.size.width;
CGFloat displayedHeight = imageRect.size.height;
CGFloat scaleX = displayedWidth / self.planWidth;
CGFloat scaleY = displayedHeight / self.planHeight;
CGFloat tapX = imageRect.origin.x + (x * scaleX);
CGFloat tapY = imageRect.origin.y + (y * scaleY);
// Visual marker
[self.markerView removeFromSuperview];
UIView *marker = [[UIView alloc] initWithFrame:CGRectMake(tapX - 6, tapY - 6, 12, 12)];
marker.backgroundColor = [UIColor redColor];
marker.layer.cornerRadius = 6;
marker.layer.borderColor = UIColor.whiteColor.CGColor;
marker.layer.borderWidth = 2.0;
[self.planImageView addSubview:marker];
self.markerView = marker;
// Try to find which location it falls inside
for (int i = 0; i < self.locations.count; i++) {
NSDictionary *locationData = self.locations[i];
if ([self isPoint:CGPointMake(tapX, tapY) insideLocation:locationData]) {
NSLog(@"✅ Auto-selected location: %@", locationData[@"name"]);
self.selectedLocation = locationData[@"name"];
self.selectionLocked = YES;
[self showAddIssuePopup];
break;
}
}
}
- (void)displayPlanImage {
if (!self.planImageURL || self.planImageURL.length == 0) {
NSLog(@"⚠️ No plan image URL found");
......
......@@ -5,5 +5,11 @@
@interface IssueAPIClient : NSObject
+ (void)fetchIssues:(void (^)(NSDictionary *data, NSError *error))completion;
+ (void)fetchVoidIssue:(id)issueID
remarks:(NSString *)remarks
completion:(void (^)(NSDictionary *data, NSError *error))completion;
+ (void)fetchDeleteIssue:(id)issueID
remarks:(NSString *)remarks
completion:(void (^)(NSDictionary *data, NSError *error))completion;
@end
......@@ -77,4 +77,146 @@
[task resume];
}
+ (void)fetchVoidIssue:(id)issueID
remarks:(NSString *)remarks
completion:(void (^)(NSDictionary *data, NSError *error))completion {
// ✅ URL
NSString *urlString = @"https://kitadev.commudesk.com/api/owner/issue/voidIssue?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"];
// json checks
NSArray *issueArray = issueID;
if (![issueID isKindOfClass:[NSArray class]]) {
issueArray = @[ issueID ?: @"" ];
}
NSString *remarksSafe = remarks ?: @"";
// ✅ Build JSON body
NSDictionary *jsonBody = @{
@"data": @{
@"os": @"AND",
@"issue_id": issueArray,
@"remarks": remarksSafe
}
};
// ✅ 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(@"✅ Void Issues API Response:\n%@", jsonResponse);
}
dispatch_async(dispatch_get_main_queue(), ^{
if (completion) completion(jsonResponse, jsonParseError);
});
}];
[task resume];
}
+ (void)fetchDeleteIssue:(NSString *)issueID
remarks:(NSString *)remarks
completion:(void (^)(NSDictionary *data, NSError *error))completion {
// ✅ URL
NSString *urlString = @"https://kitadev.commudesk.com/api/owner/issue/deleteIssue?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 *jsonBody = @{
@"data": @{
@"os": @"AND",
@"issue_id": issueID ?: @"",
@"remarks": remarks ?: @""
}
};
// ✅ 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(@"✅ Delete Issues API Response:\n%@", jsonResponse);
}
dispatch_async(dispatch_get_main_queue(), ^{
if (completion) completion(jsonResponse, jsonParseError);
});
}];
[task resume];
}
@end
#import "IssueDetailViewController.h"
#import "HistoryViewController.h"
#import "PlanViewController.h"
#import "WithdrawSingleIssueViewController.h"
@interface IssueDetailViewController ()
@interface IssueDetailViewController () <UIScrollViewDelegate>
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UIView *contentView;
......@@ -120,12 +122,19 @@
}
- (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];
CGFloat height = 230;
UIScrollView *imageScroll = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, height)];
imageScroll.pagingEnabled = YES;
imageScroll.showsHorizontalScrollIndicator = NO;
imageScroll.delegate = self;
imageScroll.tag = 777;
[self.scrollView addSubview:imageScroll];
UIPageControl *pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(0, height - 30, self.view.bounds.size.width, 20)];
pageControl.pageIndicatorTintColor = [UIColor colorWithWhite:1 alpha:0.5];
pageControl.currentPageIndicatorTintColor = UIColor.whiteColor;
pageControl.tag = 778;
[self.scrollView addSubview:pageControl];
}
- (void)setupDetailsCard {
......@@ -175,42 +184,72 @@
}
- (void)setupButtons {
CGFloat y = CGRectGetMaxY(self.detailsCard.frame) + 4;
NSString *status = [self.issueData[@"status_external"] lowercaseString];
CGFloat y = CGRectGetMaxY(self.detailsCard.frame) + 16;
CGFloat buttonWidth = (self.view.bounds.size.width - 60) / 2;
// --- Edit Button ---
UIView *buttonContainer = [[UIView alloc] initWithFrame:CGRectMake(0, y, self.view.bounds.size.width, 60)];
buttonContainer.backgroundColor = UIColor.clearColor;
[self.scrollView addSubview:buttonContainer];
// ---- Lodged ----
if ([status isEqualToString:@"lodged"]) {
// Edit Issue button
self.editButton = [UIButton buttonWithType:UIButtonTypeSystem];
self.editButton.frame = CGRectMake(20, y, buttonWidth, 44);
self.editButton.frame = CGRectMake(20, 0, 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 addTarget:self action:@selector(editIssueTapped) forControlEvents:UIControlEventTouchUpInside];
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];
[self.editButton addTarget:self action:@selector(editIssueTapped) forControlEvents:UIControlEventTouchUpInside];
[buttonContainer addSubview:self.editButton];
// --- Delete Button ---
// Delete Issue button
self.deleteButton = [UIButton buttonWithType:UIButtonTypeSystem];
self.deleteButton.frame = CGRectMake(CGRectGetMaxX(self.editButton.frame) + 20, y, buttonWidth, 44);
self.deleteButton.frame = CGRectMake(CGRectGetMaxX(self.editButton.frame) + 20, 0, buttonWidth, 44);
[self.deleteButton setTitle:@"Delete Issue" forState:UIControlStateNormal];
[self.deleteButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
[self.deleteButton addTarget:self action:@selector(deleteIssueTapped) forControlEvents:UIControlEventTouchUpInside];
self.deleteButton.backgroundColor = [UIColor systemRedColor];
self.deleteButton.layer.cornerRadius = 8;
[self.scrollView addSubview:self.deleteButton];
[self.deleteButton addTarget:self action:@selector(deleteIssueTapped) forControlEvents:UIControlEventTouchUpInside];
[buttonContainer addSubview:self.deleteButton];
}
CGFloat totalHeight = CGRectGetMaxY(self.deleteButton.frame) + 30;
self.scrollView.contentSize = CGSizeMake(self.view.bounds.size.width, totalHeight);
}
// ---- Pending Access / W.I.P ----
else if ([status isEqualToString:@"pending access"] || [status isEqualToString:@"w.i.p"] || [status isEqualToString:@"wip"]) {
UIButton *withdrawButton = [UIButton buttonWithType:UIButtonTypeSystem];
withdrawButton.frame = CGRectMake(20, 0, self.view.bounds.size.width - 40, 44);
[withdrawButton setTitle:@"Withdraw Issue" forState:UIControlStateNormal];
[withdrawButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
withdrawButton.backgroundColor = [UIColor colorWithRed:232/255.0 green:76/255.0 blue:79/255.0 alpha:1.0];
withdrawButton.layer.cornerRadius = 20;
[withdrawButton addTarget:self action:@selector(deleteIssueTapped) forControlEvents:UIControlEventTouchUpInside]; // same flow for now
[buttonContainer addSubview:withdrawButton];
}
- (void)editIssueTapped {
NSLog(@"✏️ Edit Issue tapped");
// You can later navigate to an edit screen or present a modal here
}
// ---- Pending Owner Acceptance (POA) ----
else if ([status isEqualToString:@"pending owner acceptance"]) {
CGFloat halfWidth = (self.view.bounds.size.width - 52) / 2;
- (void)deleteIssueTapped {
NSLog(@"🗑️ Delete Issue tapped");
// need to fill up later
UIButton *rejectButton = [self createAnimatedButtonWithTitle:@"Reject"
color:[UIColor colorWithRed:255/255.0 green:19/255.0 blue:6/255.0 alpha:1.0]];
rejectButton.frame = CGRectMake(20, 0, halfWidth, 44);
[buttonContainer addSubview:rejectButton];
UIButton *acceptButton = [self createAnimatedButtonWithTitle:@"Accept"
color:[UIColor colorWithRed:0/255.0 green:144/255.0 blue:14/255.0 alpha:1.0]];
acceptButton.frame = CGRectMake(CGRectGetMaxX(rejectButton.frame) + 12, 0, halfWidth, 44);
[buttonContainer addSubview:acceptButton];
}
// ---- Others ----
else {
NSLog(@"ℹ️ No action buttons for status: %@", status);
}
CGFloat totalHeight = CGRectGetMaxY(buttonContainer.frame) + 30;
self.scrollView.contentSize = CGSizeMake(self.view.bounds.size.width, totalHeight);
}
#pragma mark - Data
......@@ -221,16 +260,15 @@
NSString *ref = self.issueData[@"issue_reference"] ?: self.issueData[@"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"] ?: @"-",
createdBy[@"name"] ?: @"",
self.issueData[@"remarks"] ?: @"–"
];
......@@ -241,26 +279,117 @@
// 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];
if ([label isKindOfClass:[UILabel class]]) label.text = values[i];
}
// 🖼️ Handle multiple images
NSArray *imageList = self.issueData[@"images"];
if (![imageList isKindOfClass:[NSArray class]] || imageList.count == 0) {
// ✅ Fallback to "first" array (actual source for multiple images)
if ([self.issueData[@"first"] isKindOfClass:[NSArray class]]) {
imageList = self.issueData[@"first"];
} else if (self.issueData[@"image"]) {
imageList = @[ self.issueData[@"image"] ];
} else {
imageList = @[];
}
}
UIScrollView *imageScroll = [self.scrollView viewWithTag:777];
UIPageControl *pageControl = [self.scrollView viewWithTag:778];
CGFloat width = self.view.bounds.size.width;
CGFloat height = 230;
imageScroll.contentSize = CGSizeMake(width * imageList.count, height);
pageControl.numberOfPages = imageList.count;
pageControl.currentPage = 0;
// ✅ Remove old subviews first
for (UIView *sub in imageScroll.subviews) {
[sub removeFromSuperview];
}
for (int i = 0; i < imageList.count; i++) {
NSString *urlStr = nil;
id imgItem = imageList[i];
if ([imgItem isKindOfClass:[NSDictionary class]]) {
urlStr = imgItem[@"image"] ?: imgItem[@"thumb_image"];
} else if ([imgItem isKindOfClass:[NSString class]]) {
urlStr = imgItem;
}
if (!urlStr || urlStr.length == 0) continue;
UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(width * i, 0, width, height)];
imgView.contentMode = UIViewContentModeScaleAspectFill;
imgView.clipsToBounds = YES;
imgView.userInteractionEnabled = YES;
imgView.backgroundColor = [UIColor colorWithWhite:0.85 alpha:1];
imgView.tag = i;
// Load image
if (imageURL.length > 0) {
NSURL *url = [NSURL URLWithString:imageURL];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleImageTap:)];
[imgView addGestureRecognizer:tap];
[imageScroll addSubview:imgView];
NSURL *url = [NSURL URLWithString:urlStr];
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;
imgView.image = img;
});
}
});
}
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView.tag != 777) return; // only for the image scroll view
UIPageControl *pageControl = [self.scrollView viewWithTag:778];
CGFloat pageWidth = scrollView.frame.size.width;
NSInteger page = (NSInteger)floor((scrollView.contentOffset.x + pageWidth / 2) / pageWidth);
pageControl.currentPage = page;
}
#pragma mark - Image Tap Handler
- (void)handleImageTap:(UITapGestureRecognizer *)sender {
UIImageView *tappedImageView = (UIImageView *)sender.view;
if (!tappedImageView.image) return;
UIView *overlay = [[UIView alloc] initWithFrame:self.view.bounds];
overlay.backgroundColor = [UIColor colorWithWhite:0 alpha:0.95];
overlay.alpha = 0;
overlay.tag = 900;
overlay.userInteractionEnabled = YES;
[self.view addSubview:overlay];
UIImageView *fullImageView = [[UIImageView alloc] initWithFrame:overlay.bounds];
fullImageView.contentMode = UIViewContentModeScaleAspectFit;
fullImageView.image = tappedImageView.image;
fullImageView.userInteractionEnabled = YES;
[overlay addSubview:fullImageView];
UITapGestureRecognizer *dismissTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(closeFullImage)];
[overlay addGestureRecognizer:dismissTap];
[UIView animateWithDuration:0.25 animations:^{
overlay.alpha = 1;
}];
}
- (void)closeFullImage {
UIView *overlay = [self.view viewWithTag:900];
if (!overlay) return;
[UIView animateWithDuration:0.25 animations:^{
overlay.alpha = 0;
} completion:^(BOOL finished) {
[overlay removeFromSuperview];
}];
}
#pragma mark - Helper
- (UIColor *)colorFromHex:(NSString *)hexString {
if (!hexString || hexString.length < 6) return [UIColor grayColor];
......@@ -300,4 +429,134 @@
[self presentViewController:nextVC animated:YES completion:nil];
}
- (void)editIssueTapped {
NSLog(@"✏️ Edit Issue tapped");
NSDictionary *data = self.issueData;
if (!data || ![data isKindOfClass:[NSDictionary class]]) {
NSLog(@"⚠️ No issue data available for editing");
return;
}
// --- Prepare base values ---
NSString *issueType = @"internal";
NSString *planType = data[@"plan_type"];
if ([planType isEqualToString:@"commonarea"]) {
issueType = @"commonarea";
}
NSString *strTempUnitID = data[@"plan_id"] ? [NSString stringWithFormat:@"%@", data[@"plan_id"]] : @"";
NSString *strTempUnitName = data[@"issue_reference"] ?: @"";
NSString *strLocationName = data[@"location_name"] ?: @"";
NSString *strLocationID = data[@"location_id"] ? [NSString stringWithFormat:@"%@", data[@"location_id"]] : @"";
// --- Build issue_content dictionary ---
NSMutableDictionary *issueContent = [@{
@"id": @"temp",
@"join_id": @"",
@"pos_x": @"",
@"pos_y": @"",
@"issue_id": @""
} mutableCopy];
if (data[@"id"] && ![data[@"id"] isKindOfClass:[NSNull class]]) {
issueContent[@"issue_id"] = [NSString stringWithFormat:@"%@", data[@"id"]];
}
if (data[@"pos_x"] && ![data[@"pos_x"] isKindOfClass:[NSNull class]]) {
issueContent[@"pos_x"] = [NSString stringWithFormat:@"%@", data[@"pos_x"]];
}
if (data[@"pos_y"] && ![data[@"pos_y"] isKindOfClass:[NSNull class]]) {
issueContent[@"pos_y"] = [NSString stringWithFormat:@"%@", data[@"pos_y"]];
}
// --- Navigate to Plan Screen ---
PlanViewController *planVC = [[PlanViewController alloc] init];
planVC.modalPresentationStyle = UIModalPresentationFullScreen;
// Assign properties directly
planVC.type = issueType;
planVC.unitID = strTempUnitID;
planVC.unitName = strTempUnitName;
planVC.action = @"edit_issue";
planVC.offline = NO;
planVC.locationName = strLocationName;
planVC.locationId = strLocationID;
planVC.issueContent = issueContent;
planVC.issueFullData = data;
NSLog(@"🧭 Navigating to PlanScreen with:\n type=%@\n unitID=%@\n unitName=%@\n location= %@ & %@\n issue_id=%@\n",
planVC.type, planVC.unitID, planVC.unitName, planVC.locationName, planVC.locationId, planVC.issueContent[@"issue_id"]);
[self presentViewController:planVC animated:YES completion:nil];
}
- (void)deleteIssueTapped {
NSLog(@"🗑 Delete / Withdraw Issue tapped");
NSDictionary *data = self.issueData;
if (!data) {
NSLog(@"⚠️ No issueData available");
return;
}
// Extract values safely
NSString *issueID = [NSString stringWithFormat:@"%@", data[@"issue_reference_id"] ?: data[@"id"] ?: @""];
NSString *planID = [NSString stringWithFormat:@"%@", data[@"plan_id"] ?: @""];
NSString *status = data[@"status_external"] ?: data[@"status_internal"] ?: @"";
NSString *unitName = data[@"plan_unit"] ?: @"";
NSString *reference = data[@"issue_reference"] ?: data[@"reference"] ?: @"";
// Choose title based on context
NSString *strTitle = [status.lowercaseString containsString:@"void"]
? @"Void Issue"
: @"Delete Issue";
// ✅ Create the new VC
WithdrawSingleIssueViewController *withdrawVC = [[WithdrawSingleIssueViewController alloc] init];
withdrawVC.modalPresentationStyle = UIModalPresentationFullScreen;
// Pass data individually
withdrawVC.issueID = issueID;
withdrawVC.planID = planID;
withdrawVC.status = status;
withdrawVC.unitName = unitName;
withdrawVC.reference = reference;
withdrawVC.titleText = strTitle;
NSLog(@"📦 Navigating to WithdrawSingleIssueViewController with:\n issueID=%@\n planID=%@\n status=%@\n unitName=%@\n reference=%@\n title=%@",
issueID, planID, status, unitName, reference, strTitle);
[self presentViewController:withdrawVC animated:YES completion:nil];
}
- (UIButton *)createAnimatedButtonWithTitle:(NSString *)title color:(UIColor *)color {
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
[button setTitle:title forState:UIControlStateNormal];
[button setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
button.backgroundColor = color;
button.layer.cornerRadius = 20;
button.titleLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightRegular];
// Add tap animation
[button addTarget:self action:@selector(animateButtonTouchDown:) forControlEvents:UIControlEventTouchDown];
[button addTarget:self action:@selector(animateButtonTouchUp:) forControlEvents:UIControlEventTouchUpInside];
[button addTarget:self action:@selector(animateButtonTouchUp:) forControlEvents:UIControlEventTouchUpOutside];
return button;
}
- (void)animateButtonTouchDown:(UIButton *)button {
[UIView animateWithDuration:0.1 animations:^{
button.transform = CGAffineTransformMakeScale(0.95, 0.95);
button.alpha = 0.8;
}];
}
- (void)animateButtonTouchUp:(UIButton *)button {
[UIView animateWithDuration:0.15 animations:^{
button.transform = CGAffineTransformIdentity;
button.alpha = 1.0;
}];
}
@end
......@@ -2,6 +2,7 @@
#import "IssuesViewController.h"
#import "IssueAPIClient.h"
#import "IssueDetailViewController.h"
#import "WithdrawSingleIssueViewController.h"
#pragma mark - Internal IssueCell
@interface IssueCell : UITableViewCell
......
// WithdrawSingleIssueViewController.h
#import <UIKit/UIKit.h>
@interface WithdrawSingleIssueViewController : UIViewController
@property (nonatomic, strong) NSString *issueID;
@property (nonatomic, strong) NSString *planID;
@property (nonatomic, strong) NSString *status;
@property (nonatomic, strong) NSString *unitName;
@property (nonatomic, strong) NSString *reference;
@property (nonatomic, strong) NSString *titleText; // "Delete Issue" or "Void Issue"
@end
// WithdrawSingleIssueViewController.mm
#import "WithdrawSingleIssueViewController.h"
#import "IssueAPIClient.h"
@interface WithdrawSingleIssueViewController ()
@property (nonatomic, strong) UIView *headerView;
@property (nonatomic, strong) UIButton *backButton;
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UITextView *messageInput;
@property (nonatomic, strong) UIButton *confirmButton;
@end
@implementation WithdrawSingleIssueViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = UIColor.whiteColor;
NSLog(@"📦 Navigated to WithdrawSingleIssueViewController with:\n issueID=%@\n planID=%@\n status=%@\n unitName=%@\n reference=%@\n title=%@",
self.issueID, self.planID, self.status, self.unitName, self.reference, self.titleText);
[self setupHeader];
[self setupContent];
}
#pragma mark - Header
- (void)setupHeader {
self.headerView = [[UIView alloc] init];
self.headerView.translatesAutoresizingMaskIntoConstraints = NO;
self.headerView.backgroundColor = [UIColor colorWithRed:0/255.0 green:109/255.0 blue:141/255.0 alpha:1];
[self.view addSubview:self.headerView];
// Back button
self.backButton = [UIButton buttonWithType:UIButtonTypeSystem];
self.backButton.translatesAutoresizingMaskIntoConstraints = NO;
UIImage *backImage = [[UIImage systemImageNamed:@"chevron.left"]
imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[self.backButton setImage:backImage forState:UIControlStateNormal];
self.backButton.tintColor = UIColor.whiteColor;
[self.backButton addTarget:self
action:@selector(handleBack)
forControlEvents:UIControlEventTouchUpInside];
[self.headerView addSubview:self.backButton];
// Title label
self.titleLabel = [[UILabel alloc] init];
self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.titleLabel.text = self.titleText ?: @"Delete Issue";
self.titleLabel.textColor = UIColor.whiteColor;
self.titleLabel.font = [UIFont boldSystemFontOfSize:18];
self.titleLabel.textAlignment = NSTextAlignmentCenter;
[self.headerView addSubview:self.titleLabel];
// Layout constraints
UILayoutGuide *safe = self.view.safeAreaLayoutGuide;
[NSLayoutConstraint activateConstraints:@[
[self.headerView.topAnchor constraintEqualToAnchor:safe.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:8],
[self.backButton.centerYAnchor constraintEqualToAnchor:self.headerView.centerYAnchor],
[self.backButton.widthAnchor constraintEqualToConstant:44],
[self.backButton.heightAnchor constraintEqualToConstant:44],
[self.titleLabel.centerXAnchor constraintEqualToAnchor:self.headerView.centerXAnchor],
[self.titleLabel.centerYAnchor constraintEqualToAnchor:self.headerView.centerYAnchor]
]];
}
#pragma mark - Content
- (void)setupContent {
UILabel *promptLabel = [[UILabel alloc] init];
promptLabel.translatesAutoresizingMaskIntoConstraints = NO;
promptLabel.text = @"Write your message:";
promptLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightMedium];
[self.view addSubview:promptLabel];
self.messageInput = [[UITextView alloc] init];
self.messageInput.translatesAutoresizingMaskIntoConstraints = NO;
self.messageInput.font = [UIFont systemFontOfSize:16];
self.messageInput.layer.borderWidth = 1.0;
self.messageInput.layer.borderColor = [UIColor lightGrayColor].CGColor;
self.messageInput.layer.cornerRadius = 8;
[self.view addSubview:self.messageInput];
UIView *separator = [[UIView alloc] init];
separator.translatesAutoresizingMaskIntoConstraints = NO;
separator.backgroundColor = [UIColor colorWithWhite:0.8 alpha:1];
[self.view addSubview:separator];
self.confirmButton = [UIButton buttonWithType:UIButtonTypeSystem];
self.confirmButton.translatesAutoresizingMaskIntoConstraints = NO;
[self.confirmButton setTitle:@"Confirm" 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.titleLabel.font = [UIFont boldSystemFontOfSize:17];
self.confirmButton.layer.cornerRadius = 8;
[self.confirmButton addTarget:self action:@selector(handleConfirm)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.confirmButton];
UILayoutGuide *safe = self.view.safeAreaLayoutGuide;
[NSLayoutConstraint activateConstraints:@[
[promptLabel.topAnchor constraintEqualToAnchor:self.headerView.bottomAnchor constant:20],
[promptLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20],
[promptLabel.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-20],
[self.messageInput.topAnchor constraintEqualToAnchor:promptLabel.bottomAnchor constant:8],
[self.messageInput.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20],
[self.messageInput.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-20],
[self.messageInput.heightAnchor constraintEqualToConstant:120],
[separator.topAnchor constraintEqualToAnchor:self.messageInput.bottomAnchor constant:16],
[separator.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20],
[separator.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-20],
[separator.heightAnchor constraintEqualToConstant:1],
[self.confirmButton.topAnchor constraintEqualToAnchor:separator.bottomAnchor constant:40],
[self.confirmButton.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:40],
[self.confirmButton.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-40],
[self.confirmButton.heightAnchor constraintEqualToConstant:48]
]];
}
#pragma mark - Actions
- (void)handleBack {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)handleConfirm {
NSString *message = self.messageInput.text ?: @"";
if (message.length == 0) {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Alert"
message:@"Please enter a message before submitting."
preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"OK"
style:UIAlertActionStyleDefault
handler:nil]];
[self presentViewController:alert animated:YES completion:nil];
return;
}
// Confirmation dialog before sending
UIAlertController *confirm = [UIAlertController alertControllerWithTitle:@"Confirm"
message:@"Are you sure you want to submit?"
preferredStyle:UIAlertControllerStyleAlert];
[confirm addAction:[UIAlertAction actionWithTitle:@"No" style:UIAlertActionStyleCancel handler:nil]];
[confirm addAction:[UIAlertAction actionWithTitle:@"Yes" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
if ([self.titleText containsString:@"Delete"]) {
[self requestDeleteIssue:self.issueID remarks:message];
} else {
[self requestVoidIssue:self.issueID remarks:message];
}
}]];
[self presentViewController:confirm animated:YES completion:nil];
}
- (void)requestDeleteIssue:(NSString *)issueID remarks:(NSString *)remarks {
NSLog(@"🚀 Sending DELETE ISSUE for ID=%@, remarks=%@", issueID, remarks);
[IssueAPIClient fetchDeleteIssue:issueID remarks:remarks completion:^(NSDictionary *data, NSError *error) {
if (error) {
NSLog(@"Error %@", error.localizedDescription);
return;
}
NSDictionary *appData = data[@"AppData"];
if ([appData[@"status"] isEqualToString:@"success"]) {
NSLog(@"Issue deleted successfully");
} else {
NSString *message = appData[@"message"] ?: @"Unknown error";
NSLog(@"Error Message %@", message);
}
}];
}
- (void)requestVoidIssue:(NSString *)issueID remarks:(NSString *)remarks {
NSLog(@"🚀 Sending VOID ISSUE for ID=%@, remarks=%@", issueID, remarks);
NSArray *issueArray = @[ issueID ?: @"" ];
[IssueAPIClient fetchVoidIssue:issueArray remarks:remarks completion:^(NSDictionary *data, NSError *error) {
if (error) {
NSLog(@"Error %@", error.localizedDescription);
return;
}
NSDictionary *appData = data[@"AppData"];
if ([appData[@"status"] isEqualToString:@"success"]) {
NSLog(@"Issue withdrawn successfully");
} else {
NSString *message = appData[@"message"] ?: @"Unknown error";
NSLog(@"Error Message %@", message);
}
}];
}
@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