Commit 7b821f42 authored by Wei Han's avatar Wei Han

code update

parent 14d0d71c
...@@ -9,9 +9,9 @@ ...@@ -9,9 +9,9 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
44006126336D83DB220E7214 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */; }; 44006126336D83DB220E7214 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */; };
4EC822DE2B433513F31AFB3E /* libPods-example.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40EB36954DDA100CF0424A89 /* libPods-example.a */; };
761780ED2CA45674006654EE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761780EC2CA45674006654EE /* AppDelegate.swift */; }; 761780ED2CA45674006654EE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761780EC2CA45674006654EE /* AppDelegate.swift */; };
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; }; 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
AFC1B725D41173F56B62FA3B /* libPods-example.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F2A6CDBD96A29E1979EF0BD3 /* libPods-example.a */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
...@@ -19,12 +19,12 @@ ...@@ -19,12 +19,12 @@
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = example/Images.xcassets; sourceTree = "<group>"; }; 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = example/Images.xcassets; sourceTree = "<group>"; };
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = example/Info.plist; sourceTree = "<group>"; }; 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = example/Info.plist; sourceTree = "<group>"; };
13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = PrivacyInfo.xcprivacy; path = example/PrivacyInfo.xcprivacy; sourceTree = "<group>"; }; 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = PrivacyInfo.xcprivacy; path = example/PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
31FDB50C78AE137D41CF411D /* Pods-example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example.debug.xcconfig"; path = "Target Support Files/Pods-example/Pods-example.debug.xcconfig"; sourceTree = "<group>"; };
40EB36954DDA100CF0424A89 /* libPods-example.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-example.a"; sourceTree = BUILT_PRODUCTS_DIR; };
761780EC2CA45674006654EE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = example/AppDelegate.swift; sourceTree = "<group>"; }; 761780EC2CA45674006654EE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = example/AppDelegate.swift; sourceTree = "<group>"; };
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = example/LaunchScreen.storyboard; sourceTree = "<group>"; }; 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = example/LaunchScreen.storyboard; sourceTree = "<group>"; };
824AEC708BA04F5AD482851A /* Pods-example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example.release.xcconfig"; path = "Target Support Files/Pods-example/Pods-example.release.xcconfig"; sourceTree = "<group>"; }; 9585DFA7130596921EB0F5A6 /* Pods-example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example.release.xcconfig"; path = "Target Support Files/Pods-example/Pods-example.release.xcconfig"; sourceTree = "<group>"; };
C92BFB68E35543E7EF3282FC /* Pods-example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-example.debug.xcconfig"; path = "Target Support Files/Pods-example/Pods-example.debug.xcconfig"; sourceTree = "<group>"; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
F2A6CDBD96A29E1979EF0BD3 /* libPods-example.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-example.a"; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
4EC822DE2B433513F31AFB3E /* libPods-example.a in Frameworks */, AFC1B725D41173F56B62FA3B /* libPods-example.a in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
ED297162215061F000B7C4FE /* JavaScriptCore.framework */, ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
40EB36954DDA100CF0424A89 /* libPods-example.a */, F2A6CDBD96A29E1979EF0BD3 /* libPods-example.a */,
); );
name = Frameworks; name = Frameworks;
sourceTree = "<group>"; sourceTree = "<group>";
...@@ -92,8 +92,8 @@ ...@@ -92,8 +92,8 @@
BBD78D7AC51CEA395F1C20DB /* Pods */ = { BBD78D7AC51CEA395F1C20DB /* Pods */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
31FDB50C78AE137D41CF411D /* Pods-example.debug.xcconfig */, C92BFB68E35543E7EF3282FC /* Pods-example.debug.xcconfig */,
824AEC708BA04F5AD482851A /* Pods-example.release.xcconfig */, 9585DFA7130596921EB0F5A6 /* Pods-example.release.xcconfig */,
); );
path = Pods; path = Pods;
sourceTree = "<group>"; sourceTree = "<group>";
...@@ -105,13 +105,13 @@ ...@@ -105,13 +105,13 @@
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "example" */; buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "example" */;
buildPhases = ( buildPhases = (
B87419CC63186335BB42ACC9 /* [CP] Check Pods Manifest.lock */, 94C2598371F476B4E1E60F33 /* [CP] Check Pods Manifest.lock */,
13B07F871A680F5B00A75B9A /* Sources */, 13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */, 13B07F8C1A680F5B00A75B9A /* Frameworks */,
13B07F8E1A680F5B00A75B9A /* Resources */, 13B07F8E1A680F5B00A75B9A /* Resources */,
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
7EA22330F9EEADB32B8DCA0C /* [CP] Embed Pods Frameworks */, 97557091BD8C2C7B4B6F7AD4 /* [CP] Embed Pods Frameworks */,
CF5916958D0840FF3C063407 /* [CP] Copy Pods Resources */, 052C3E3D9666B087C0F21867 /* [CP] Copy Pods Resources */,
); );
buildRules = ( buildRules = (
); );
...@@ -183,24 +183,24 @@ ...@@ -183,24 +183,24 @@
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "set -e\n\nWITH_ENVIRONMENT=\"$REACT_NATIVE_PATH/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"$REACT_NATIVE_PATH/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n"; shellScript = "set -e\n\nWITH_ENVIRONMENT=\"$REACT_NATIVE_PATH/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"$REACT_NATIVE_PATH/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n";
}; };
7EA22330F9EEADB32B8DCA0C /* [CP] Embed Pods Frameworks */ = { 052C3E3D9666B087C0F21867 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
); );
inputFileListPaths = ( inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-frameworks-${CONFIGURATION}-input-files.xcfilelist", "${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-resources-${CONFIGURATION}-input-files.xcfilelist",
); );
name = "[CP] Embed Pods Frameworks"; name = "[CP] Copy Pods Resources";
outputFileListPaths = ( outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-frameworks-${CONFIGURATION}-output-files.xcfilelist", "${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-resources-${CONFIGURATION}-output-files.xcfilelist",
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-frameworks.sh\"\n"; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-resources.sh\"\n";
showEnvVarsInLog = 0; showEnvVarsInLog = 0;
}; };
B87419CC63186335BB42ACC9 /* [CP] Check Pods Manifest.lock */ = { 94C2598371F476B4E1E60F33 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
...@@ -222,21 +222,21 @@ ...@@ -222,21 +222,21 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0; showEnvVarsInLog = 0;
}; };
CF5916958D0840FF3C063407 /* [CP] Copy Pods Resources */ = { 97557091BD8C2C7B4B6F7AD4 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
); );
inputFileListPaths = ( inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-resources-${CONFIGURATION}-input-files.xcfilelist", "${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-frameworks-${CONFIGURATION}-input-files.xcfilelist",
); );
name = "[CP] Copy Pods Resources"; name = "[CP] Embed Pods Frameworks";
outputFileListPaths = ( outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-resources-${CONFIGURATION}-output-files.xcfilelist", "${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-frameworks-${CONFIGURATION}-output-files.xcfilelist",
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-resources.sh\"\n"; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-frameworks.sh\"\n";
showEnvVarsInLog = 0; showEnvVarsInLog = 0;
}; };
/* End PBXShellScriptBuildPhase section */ /* End PBXShellScriptBuildPhase section */
...@@ -255,7 +255,7 @@ ...@@ -255,7 +255,7 @@
/* Begin XCBuildConfiguration section */ /* Begin XCBuildConfiguration section */
13B07F941A680F5B00A75B9A /* Debug */ = { 13B07F941A680F5B00A75B9A /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 31FDB50C78AE137D41CF411D /* Pods-example.debug.xcconfig */; baseConfigurationReference = C92BFB68E35543E7EF3282FC /* Pods-example.debug.xcconfig */;
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
...@@ -283,7 +283,7 @@ ...@@ -283,7 +283,7 @@
}; };
13B07F951A680F5B00A75B9A /* Release */ = { 13B07F951A680F5B00A75B9A /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 824AEC708BA04F5AD482851A /* Pods-example.release.xcconfig */; baseConfigurationReference = 9585DFA7130596921EB0F5A6 /* Pods-example.release.xcconfig */;
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<dict> <dict>
<key>Assets.car</key> <key>Assets.car</key>
<data> <data>
mDeq0E4lblXfFuIgkojjE5zY6hk= nz4CVgVrIgti3Z6dGyfqT52lO7E=
</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>
/JZsUWwwr7A+ZF0o001HQXRnzpI= t43yRjSptMFTXQfSxY21jokBVtU=
</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>
0+eonZqFOeyimWUH94CuUhfXNEulhfi9YeuUE/wnX0s= J60ydBHIUa66OEr3jc21333AHp87l+VEFvKU7h3lu2M=
</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>
mDeq0E4lblXfFuIgkojjE5zY6hk= nz4CVgVrIgti3Z6dGyfqT52lO7E=
</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>
4pQwOIuYwsUH4Iiw1M402s3Ii8Y= CSlwpYePP8U03s3cRC5622W7ESM=
</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>
0+eonZqFOeyimWUH94CuUhfXNEulhfi9YeuUE/wnX0s= J60ydBHIUa66OEr3jc21333AHp87l+VEFvKU7h3lu2M=
</data> </data>
</dict> </dict>
<key>Headers/QmsPlugin.h</key> <key>Headers/QmsPlugin.h</key>
......
// AccessAppointmentViewController.h
#import <UIKit/UIKit.h>
@interface AccessAppointmentViewController : UIViewController
@property (nonatomic, strong) NSDictionary *appointmentData;
@end
// AccessAppointmentViewController.mm
#import "AccessAppointmentViewController.h"
@interface AccessAppointmentViewController ()
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UIView *contentView;
@property (nonatomic, strong) UIView *header;
@property (nonatomic, strong) UILabel *unitLabel;
// Top unit section
@property (nonatomic, strong) UIView *unitLine;
// Card + fields
@property (nonatomic, strong) UIView *cardView;
@property (nonatomic, strong) UILabel *typeValueLabel;
@property (nonatomic, strong) UILabel *dateValueLabel;
@property (nonatomic, strong) UILabel *timeValueLabel;
@property (nonatomic, strong) UILabel *issuesLabel;
// Buttons
@property (nonatomic, strong) UIButton *cancelButton;
@property (nonatomic, strong) UIButton *calendarButton;
@property (nonatomic, assign) BOOL canCancel;
@end
@implementation AccessAppointmentViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor colorWithWhite:0.98 alpha:1];
// Build UI
[self setupHeader];
[self setupScrollView];
[self setupUnitSection];
[self setupAppointmentCard];
[self setupIssuesSection];
[self setupActionButtonsIfNeeded];
// Fill data
[self populateData];
}
#pragma mark - Header
- (void)setupHeader {
self.header = [[UIView alloc] init];
self.header.translatesAutoresizingMaskIntoConstraints = NO;
self.header.backgroundColor = [UIColor colorWithRed:0 green:0.45 blue:0.55 alpha:1];
[self.view addSubview:self.header];
UILabel *titleLabel = [[UILabel alloc] init];
titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
titleLabel.textColor = UIColor.whiteColor;
titleLabel.font = [UIFont boldSystemFontOfSize:18];
titleLabel.text = @"Rectification Appointment";
[self.header addSubview:titleLabel];
UIButton *backBtn = [UIButton buttonWithType:UIButtonTypeSystem];
backBtn.translatesAutoresizingMaskIntoConstraints = NO;
[backBtn setImage:[UIImage systemImageNamed:@"chevron.backward"] forState:UIControlStateNormal];
backBtn.tintColor = UIColor.whiteColor;
[backBtn addTarget:self action:@selector(onBack) forControlEvents:UIControlEventTouchUpInside];
[self.header addSubview:backBtn];
[NSLayoutConstraint activateConstraints:@[
[self.header.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor],
[self.header.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.header.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.header.heightAnchor constraintEqualToConstant:48],
[backBtn.leadingAnchor constraintEqualToAnchor:self.header.leadingAnchor constant:12],
[backBtn.centerYAnchor constraintEqualToAnchor:self.header.centerYAnchor],
[titleLabel.centerXAnchor constraintEqualToAnchor:self.header.centerXAnchor],
[titleLabel.centerYAnchor constraintEqualToAnchor:self.header.centerYAnchor],
]];
}
#pragma mark - Scroll container
- (void)setupScrollView {
self.scrollView = [[UIScrollView alloc] init];
self.scrollView.translatesAutoresizingMaskIntoConstraints = NO;
self.scrollView.alwaysBounceVertical = YES;
[self.view addSubview:self.scrollView];
self.contentView = [[UIView alloc] init];
self.contentView.translatesAutoresizingMaskIntoConstraints = NO;
[self.scrollView addSubview:self.contentView];
[NSLayoutConstraint activateConstraints:@[
[self.scrollView.topAnchor constraintEqualToAnchor:self.header.bottomAnchor constant:10],
[self.scrollView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.scrollView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.scrollView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor],
[self.contentView.topAnchor constraintEqualToAnchor:self.scrollView.topAnchor],
[self.contentView.leadingAnchor constraintEqualToAnchor:self.scrollView.leadingAnchor],
[self.contentView.trailingAnchor constraintEqualToAnchor:self.scrollView.trailingAnchor],
[self.contentView.bottomAnchor constraintEqualToAnchor:self.scrollView.bottomAnchor],
[self.contentView.widthAnchor constraintEqualToAnchor:self.scrollView.widthAnchor]
]];
}
#pragma mark - Unit header section
- (void)setupUnitSection {
UILabel *forLabel = [[UILabel alloc] init];
forLabel.translatesAutoresizingMaskIntoConstraints = NO;
forLabel.text = @"For Unit No. :";
forLabel.font = [UIFont systemFontOfSize:15 weight:UIFontWeightRegular];
forLabel.textColor = [UIColor darkGrayColor];
[self.contentView addSubview:forLabel];
self.unitLabel = [[UILabel alloc] init];
self.unitLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.unitLabel.font = [UIFont systemFontOfSize:28 weight:UIFontWeightBold];
self.unitLabel.textColor = [UIColor blackColor];
[self.contentView addSubview:self.unitLabel];
UIView *separator = [[UIView alloc] init];
separator.translatesAutoresizingMaskIntoConstraints = NO;
separator.backgroundColor = [UIColor colorWithWhite:0.85 alpha:1];
[self.contentView addSubview:separator];
self.unitLine = separator;
[NSLayoutConstraint activateConstraints:@[
[forLabel.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:18],
[forLabel.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
[self.unitLabel.topAnchor constraintEqualToAnchor:forLabel.bottomAnchor constant:6],
[self.unitLabel.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
[separator.topAnchor constraintEqualToAnchor:self.unitLabel.bottomAnchor constant:16],
[separator.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
[separator.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-16],
[separator.heightAnchor constraintEqualToConstant:1]
]];
}
#pragma mark - Appointment Card
- (void)setupAppointmentCard {
self.cardView = [[UIView alloc] init];
self.cardView.translatesAutoresizingMaskIntoConstraints = NO;
self.cardView.backgroundColor = UIColor.whiteColor;
self.cardView.layer.cornerRadius = 12;
self.cardView.layer.shadowColor = [UIColor blackColor].CGColor;
self.cardView.layer.shadowOpacity = 0.06;
self.cardView.layer.shadowRadius = 6;
self.cardView.layer.shadowOffset = CGSizeMake(0, 3);
[self.contentView addSubview:self.cardView];
// Title
UILabel *title = [[UILabel alloc] init];
title.translatesAutoresizingMaskIntoConstraints = NO;
title.text = @"Appointment Info";
title.font = [UIFont boldSystemFontOfSize:18];
[self.cardView addSubview:title];
// Type label + pill
UILabel *typeLabel = [self lightLabelWithText:@"Type :"];
[self.cardView addSubview:typeLabel];
self.typeValueLabel = [self pillLabel:@"Rectification"];
[self.cardView addSubview:self.typeValueLabel];
// Calendar button (right)
self.calendarButton = [self calendarBoxButton];
[self.cardView addSubview:self.calendarButton];
// Date
UILabel *dateLabel = [self lightLabelWithText:@"Date :"];
[self.cardView addSubview:dateLabel];
self.dateValueLabel = [self regularLabelWithText:@"--"];
[self.cardView addSubview:self.dateValueLabel];
// Time
UILabel *timeLabel = [self lightLabelWithText:@"Time Slot :"];
[self.cardView addSubview:timeLabel];
self.timeValueLabel = [self regularLabelWithText:@"--"];
[self.cardView addSubview:self.timeValueLabel];
// Layout constraints
[NSLayoutConstraint activateConstraints:@[
[self.cardView.topAnchor constraintEqualToAnchor:self.unitLine.bottomAnchor constant:18],
[self.cardView.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
[self.cardView.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-16],
[title.topAnchor constraintEqualToAnchor:self.cardView.topAnchor constant:16],
[title.leadingAnchor constraintEqualToAnchor:self.cardView.leadingAnchor constant:16],
[typeLabel.topAnchor constraintEqualToAnchor:title.bottomAnchor constant:18],
[typeLabel.leadingAnchor constraintEqualToAnchor:self.cardView.leadingAnchor constant:16],
[self.typeValueLabel.centerYAnchor constraintEqualToAnchor:typeLabel.centerYAnchor],
[self.typeValueLabel.leadingAnchor constraintEqualToAnchor:typeLabel.trailingAnchor constant:8],
[self.calendarButton.centerYAnchor constraintEqualToAnchor:self.typeValueLabel.centerYAnchor],
[self.calendarButton.trailingAnchor constraintEqualToAnchor:self.cardView.trailingAnchor constant:-12],
[self.calendarButton.widthAnchor constraintEqualToConstant:92],
[self.calendarButton.heightAnchor constraintEqualToConstant:46],
[dateLabel.topAnchor constraintEqualToAnchor:typeLabel.bottomAnchor constant:18],
[dateLabel.leadingAnchor constraintEqualToAnchor:self.cardView.leadingAnchor constant:16],
[self.dateValueLabel.centerYAnchor constraintEqualToAnchor:dateLabel.centerYAnchor],
[self.dateValueLabel.leadingAnchor constraintEqualToAnchor:dateLabel.trailingAnchor constant:8],
[timeLabel.topAnchor constraintEqualToAnchor:dateLabel.bottomAnchor constant:14],
[timeLabel.leadingAnchor constraintEqualToAnchor:self.cardView.leadingAnchor constant:16],
[self.timeValueLabel.centerYAnchor constraintEqualToAnchor:timeLabel.centerYAnchor],
[self.timeValueLabel.leadingAnchor constraintEqualToAnchor:timeLabel.trailingAnchor constant:8],
// bottom anchor of card (provides contentView sizing)
[self.timeValueLabel.bottomAnchor constraintEqualToAnchor:self.cardView.bottomAnchor constant:-18]
]];
}
#pragma mark - Issues section
- (void)setupIssuesSection {
UILabel *title = [[UILabel alloc] init];
title.translatesAutoresizingMaskIntoConstraints = NO;
title.text = @"Issue(s) Info";
title.font = [UIFont boldSystemFontOfSize:18];
[self.contentView addSubview:title];
self.issuesLabel = [self regularLabelWithText:@"--"];
self.issuesLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.issuesLabel.numberOfLines = 0;
[self.contentView addSubview:self.issuesLabel];
[NSLayoutConstraint activateConstraints:@[
[title.topAnchor constraintEqualToAnchor:self.cardView.bottomAnchor constant:20],
[title.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
[self.issuesLabel.topAnchor constraintEqualToAnchor:title.bottomAnchor constant:10],
[self.issuesLabel.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
[self.issuesLabel.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-16],
[self.issuesLabel.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor constant:-30]
]];
}
#pragma mark - Action Buttons (Cancel + optional)
- (void)setupActionButtonsIfNeeded {
// If you always want to show cancel, set this to YES. Otherwise compute based on date/status.
BOOL shouldShowCancel = NO; // default: no
// If appointmentData includes a "can_cancel" key, respect it:
if (self.appointmentData[@"can_cancel"]) {
shouldShowCancel = [self.appointmentData[@"can_cancel"] boolValue];
}
if (!shouldShowCancel) return;
// Cancel button
self.cancelButton = [UIButton buttonWithType:UIButtonTypeSystem];
self.cancelButton.translatesAutoresizingMaskIntoConstraints = NO;
self.cancelButton.backgroundColor = [UIColor colorWithRed:0.86 green:0.27 blue:0.36 alpha:1]; // red
[self.cancelButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
[self.cancelButton setTitle:@"Cancel Appointment" forState:UIControlStateNormal];
self.cancelButton.layer.cornerRadius = 10;
[self.cancelButton addTarget:self action:@selector(cancelPressed) forControlEvents:UIControlEventTouchUpInside];
[self.contentView addSubview:self.cancelButton];
[NSLayoutConstraint activateConstraints:@[
[self.cancelButton.topAnchor constraintEqualToAnchor:self.cardView.bottomAnchor constant:20],
[self.cancelButton.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
[self.cancelButton.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-16],
[self.cancelButton.heightAnchor constraintEqualToConstant:52],
[self.cancelButton.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor constant:-24]
]];
}
#pragma mark - Populate data
- (void)populateData {
// appointmentData expected keys: unit_no, type, date, time_slot, issues
if (self.appointmentData == nil) return;
NSString *unitNo = self.appointmentData[@"unit_no"] ?: @"--";
self.unitLabel.text = unitNo;
NSString *type = self.appointmentData[@"type"] ?: @"Rectification";
self.typeValueLabel.text = type;
// date parsing: accepts yyyy-MM-dd or server format; fallback to raw string
NSString *rawDate = self.appointmentData[@"date"];
if (rawDate) {
NSString *formatted = [self formattedDateStringFromRaw:rawDate];
self.dateValueLabel.text = formatted;
}
NSString *timeSlot = self.appointmentData[@"time_slot"] ?: self.appointmentData[@"time"] ?: @"--";
self.timeValueLabel.text = timeSlot;
NSString *issues = self.appointmentData[@"issues"];
if (!issues && self.appointmentData[@"issue_list"]) {
NSArray *arr = self.appointmentData[@"issue_list"];
issues = [arr componentsJoinedByString:@"\n"];
}
self.issuesLabel.text = issues ?: @"No issues specified";
}
#pragma mark - Helpers / UI helpers
- (UILabel *)lightLabelWithText:(NSString *)text {
UILabel *lbl = [[UILabel alloc] init];
lbl.translatesAutoresizingMaskIntoConstraints = NO;
lbl.text = text;
lbl.font = [UIFont systemFontOfSize:15 weight:UIFontWeightRegular];
lbl.textColor = [UIColor darkGrayColor];
return lbl;
}
- (UILabel *)regularLabelWithText:(NSString *)text {
UILabel *lbl = [[UILabel alloc] init];
lbl.translatesAutoresizingMaskIntoConstraints = NO;
lbl.text = text;
lbl.font = [UIFont systemFontOfSize:16 weight:UIFontWeightRegular];
lbl.textColor = [UIColor blackColor];
return lbl;
}
- (UILabel *)pillLabel:(NSString *)text {
UILabel *lbl = [[UILabel alloc] init];
lbl.translatesAutoresizingMaskIntoConstraints = NO;
lbl.text = text;
lbl.textAlignment = NSTextAlignmentCenter;
lbl.font = [UIFont boldSystemFontOfSize:14];
lbl.textColor = UIColor.whiteColor;
lbl.backgroundColor = [UIColor colorWithRed:1.0 green:0.55 blue:0.2 alpha:1];
lbl.layer.cornerRadius = 14;
lbl.clipsToBounds = YES;
// fixed intrinsic size constraints for pill appearance
[NSLayoutConstraint activateConstraints:@[
[lbl.widthAnchor constraintGreaterThanOrEqualToConstant:100],
[lbl.heightAnchor constraintEqualToConstant:28]
]];
return lbl;
}
- (UIButton *)calendarBoxButton {
UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem];
btn.translatesAutoresizingMaskIntoConstraints = NO;
btn.layer.cornerRadius = 8;
btn.layer.borderWidth = 1;
btn.layer.borderColor = [UIColor colorWithWhite:0.85 alpha:1].CGColor;
// Compose text + icon using title + image
UIImage *icon = [UIImage systemImageNamed:@"calendar"];
[btn setImage:icon forState:UIControlStateNormal];
btn.tintColor = [UIColor darkGrayColor];
// multiline title
[btn setTitle:@" Add To\n Calendar" forState:UIControlStateNormal];
btn.titleLabel.numberOfLines = 2;
btn.titleLabel.font = [UIFont systemFontOfSize:12];
btn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
btn.imageEdgeInsets = UIEdgeInsetsMake(8, 8, 8, 0);
btn.titleEdgeInsets = UIEdgeInsetsMake(6, 4, 6, 8);
[btn addTarget:self action:@selector(addToCalendarTapped) forControlEvents:UIControlEventTouchUpInside];
return btn;
}
#pragma mark - Date formatting
- (NSString *)formattedDateStringFromRaw:(NSString *)raw {
if (!raw) return @"--";
// try common formats
NSArray<NSString *> *formats = @[@"yyyy-MM-dd", @"yyyy-MM-dd HH:mm:ss", @"yyyy-MM-dd'T'HH:mm:ss'Z'"];
NSDate *d = nil;
NSDateFormatter *inFmt = [[NSDateFormatter alloc] init];
inFmt.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
for (NSString *fmt in formats) {
inFmt.dateFormat = fmt;
d = [inFmt dateFromString:raw];
if (d) break;
}
if (!d) return raw; // fallback
NSDateFormatter *out = [[NSDateFormatter alloc] init];
out.locale = [NSLocale localeWithLocaleIdentifier:@"en_US"];
out.dateFormat = @"dd MMM yyyy";
return [out stringFromDate:d];
}
#pragma mark - Actions
- (void)onBack {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)addToCalendarTapped {
// Hook: create event using EventKit if you want
UIAlertController *a = [UIAlertController alertControllerWithTitle:@"Add to Calendar"
message:@"Calendar integration not implemented yet."
preferredStyle:UIAlertControllerStyleAlert];
[a addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
[self presentViewController:a animated:YES completion:nil];
}
- (void)cancelPressed {
UIAlertController *confirm = [UIAlertController alertControllerWithTitle:@"Cancel Appointment"
message:@"Are you sure you want to cancel this appointment?"
preferredStyle:UIAlertControllerStyleAlert];
[confirm addAction:[UIAlertAction actionWithTitle:@"No" style:UIAlertActionStyleCancel handler:nil]];
[confirm addAction:[UIAlertAction actionWithTitle:@"Yes" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
[self showReasonPopupForCancellation];
}]];
[self presentViewController:confirm animated:YES completion:nil];
}
- (void)showReasonPopupForCancellation {
UIAlertController *reasonAlert =
[UIAlertController alertControllerWithTitle:@"Reason for Cancellation"
message:@"Please tell us why you want to cancel this appointment."
preferredStyle:UIAlertControllerStyleAlert];
[reasonAlert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.placeholder = @"Enter reason...";
}];
[reasonAlert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
[reasonAlert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
NSString *remarks = reasonAlert.textFields.firstObject.text ?: @"";
[self sendCancellationRequestWithReason:remarks];
}]];
[self presentViewController:reasonAlert animated:YES completion:nil];
}
- (void)sendCancellationRequestWithReason:(NSString *)remarks {
if (remarks.length == 0) remarks = @"No reason provided";
if (!self.appointmentData[@"id"]) {
NSLog(@"No appointment id, aborting cancellation");
return;
}
// call API - placeholder
// [AppointmentAPIClient fetchCancelAppointment:self.appointmentData[@"id"] reason:remarks completion:...]
// For now simulate success:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
UIAlertController *status = [UIAlertController alertControllerWithTitle:@"Appointment Cancelled"
message:@"Your appointment has been cancelled."
preferredStyle:UIAlertControllerStyleAlert];
[status addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[self dismissViewControllerAnimated:YES completion:nil];
}]];
[self presentViewController:status animated:YES completion:nil];
});
}
@end
// AccessItemAPIClient.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface AccessItemAPIClient : NSObject
+ (void)fetchAccessItem:(NSString *)unitId
completion:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion;
@end
NS_ASSUME_NONNULL_END
// AccessItemAPIClient.mm
#import "AccessItemAPIClient.h"
@implementation AccessItemAPIClient
+ (void)fetchAccessItem:(NSString *)unitId
completion:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion {
NSString *urlString = @"https://kitadev.commudesk.com/api/owner/plan/getAccessItem?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6ImF0aGlyYWh6YWlkaUBjb252ZXAuY29tIiwicGFzc3dvcmQiOiIkMnkkMTAkNU9xYklqMnZ6UHJwckJrcVd5c3I2LmJCc1hVYS9Hd014eUhnL3RhUUhPUkNQcGdmTG8yakciLCJzdWIiOjIxNzAsImlzcyI6Imh0dHBzOi8va2l0YWRldi5jb21tdWRlc2suY29tL2FwaS9vd25lci9hdXRoL3Bhc3N3b3JkbGVzc19sb2dpbiIsImlhdCI6MTc2MDMxNTM1MiwiZXhwIjoyMDc1ODg0ODcyLCJuYmYiOjE3NjAzMTUzNTIsImp0aSI6IktoQmNyQnJEdDVNdDZlWmMifQ.JnxGbZ7hTeoOr6oibIzZMphgyKtTo2Aq9Efx6mrGfFA";
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
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": unitId ?: @"",
@"information": deviceInfo,
}
};
NSLog(@"🌍 SUBMIT URL: %@", urlString);
NSLog(@"📦 SUBMIT Body JSON: %@", jsonBody);
NSError *jsonError;
NSData *bodyData = [NSJSONSerialization dataWithJSONObject:jsonBody options:0 error:&jsonError];
if (jsonError) {
NSLog(@"❌ JSON Serialization Error: %@", jsonError);
if (completion) completion(NO, nil, jsonError);
return;
}
request.HTTPBody = bodyData;
NSLog(@"🔄 SUBMIT (NO REP) Request started...");
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(), ^{
completion(NO, nil, error);
});
return;
}
NSError *parseError;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
if (parseError) {
NSLog(@"⚠️ JSON Parse Error: %@", parseError);
dispatch_async(dispatch_get_main_queue(), ^{
completion(NO, nil, parseError);
});
return;
}
NSLog(@"✅ SUBMIT (NO REP) API Response:\n%@", json);
dispatch_async(dispatch_get_main_queue(), ^{
completion(YES, json, nil);
});
}];
[task resume];
}
@end
// AccessItemViewController.h
#import <UIKit/UIKit.h>
typedef NS_ENUM(NSInteger, DisplayPage) {
DisplayPageAccessItem,
DisplayPageTransactionContent,
DisplayPageAppointmentContent
};
@interface AccessItemViewController : UIViewController
// Data
@property (nonatomic, strong) NSArray *submittedItems;
@property (nonatomic, strong) NSArray *transactionItems;
@property (nonatomic, strong) NSDictionary *selectedTransaction;
@property (nonatomic, strong) NSString *unitID;
@property (nonatomic, strong) NSString *unitName;
@end
// AccessItemViewController.m
#import "AccessItemViewController.h"
#import "AccessItemAPIClient.h"
#import "AppointmentAPIClient.h"
#import <UIKit/UIKit.h>
#import "AccessAppointmentViewController.h"
#import "AccessTransactionViewController.h"
// Custom Card
@interface SubmittedItemCell : UITableViewCell
@property (nonatomic, strong) UIImageView *iconView;
@property (nonatomic, strong) UILabel *nameLabel;
@property (nonatomic, strong) UILabel *codeLabel;
@property (nonatomic, strong) UILabel *possessor;
@property (nonatomic, strong) UIView *cardView;
- (void)configureWithItem:(NSDictionary *)item;
@end
@implementation SubmittedItemCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (!self) return nil;
self.selectionStyle = UITableViewCellSelectionStyleNone;
// Card container
self.cardView = [[UIView alloc] init];
self.cardView.translatesAutoresizingMaskIntoConstraints = NO;
self.cardView.layer.cornerRadius = 12;
self.cardView.backgroundColor = UIColor.whiteColor;
self.cardView.layer.shadowColor = [UIColor blackColor].CGColor;
self.cardView.layer.shadowOpacity = 0.05;
self.cardView.layer.shadowRadius = 4;
self.cardView.layer.shadowOffset = CGSizeMake(0, 2);
[self.contentView addSubview:self.cardView];
[NSLayoutConstraint activateConstraints:@[
[self.cardView.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:8],
[self.cardView.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor constant:-8],
[self.cardView.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
[self.cardView.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-16],
]];
self.iconView = [[UIImageView alloc] init];
self.iconView.translatesAutoresizingMaskIntoConstraints = NO;
self.iconView.contentMode = UIViewContentModeScaleAspectFit;
[self.cardView addSubview:self.iconView];
self.possessor = [[UILabel alloc] init];
self.possessor.translatesAutoresizingMaskIntoConstraints = NO;
self.possessor.font = [UIFont boldSystemFontOfSize:16];
[self.cardView addSubview:self.possessor];
self.nameLabel = [[UILabel alloc] init];
self.nameLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.nameLabel.font = [UIFont systemFontOfSize:14];
[self.cardView addSubview:self.nameLabel];
self.codeLabel = [[UILabel alloc] init];
self.codeLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.codeLabel.font = [UIFont systemFontOfSize:14];
self.codeLabel.textColor = UIColor.darkGrayColor;
[self.cardView addSubview:self.codeLabel];
self.possessor.numberOfLines = 0;
self.nameLabel.numberOfLines = 0;
self.codeLabel.numberOfLines = 0;
[self setupConstraints];
return self;
}
- (void)setupConstraints {
[NSLayoutConstraint activateConstraints:@[
[self.iconView.leadingAnchor constraintEqualToAnchor:self.cardView.leadingAnchor constant:12],
[self.iconView.topAnchor constraintEqualToAnchor:self.cardView.topAnchor constant:12],
[self.iconView.widthAnchor constraintEqualToConstant:32],
[self.iconView.heightAnchor constraintEqualToConstant:32],
[self.possessor.leadingAnchor constraintEqualToAnchor:self.iconView.trailingAnchor constant:12],
[self.possessor.trailingAnchor constraintEqualToAnchor:self.cardView.trailingAnchor constant:-12],
[self.possessor.topAnchor constraintEqualToAnchor:self.cardView.topAnchor constant:12],
[self.nameLabel.leadingAnchor constraintEqualToAnchor:self.possessor.leadingAnchor],
[self.nameLabel.trailingAnchor constraintEqualToAnchor:self.possessor.trailingAnchor],
[self.nameLabel.topAnchor constraintEqualToAnchor:self.possessor.bottomAnchor constant:4],
[self.codeLabel.leadingAnchor constraintEqualToAnchor:self.possessor.leadingAnchor],
[self.codeLabel.trailingAnchor constraintEqualToAnchor:self.possessor.trailingAnchor],
[self.codeLabel.topAnchor constraintEqualToAnchor:self.nameLabel.bottomAnchor constant:4],
[self.codeLabel.bottomAnchor constraintEqualToAnchor:self.cardView.bottomAnchor constant:-12]
]];
}
- (UIImage *)iconForPossessor:(NSString *)possessor {
if ([possessor.lowercaseString containsString:@"owner"]) {
return [UIImage imageNamed:@"icon_owner"];
}
return [UIImage imageNamed:@"icon_other"];
}
- (void)configureWithItem:(NSDictionary *)item {
self.nameLabel.text = item[@"name"] ?: @"";
self.codeLabel.text = item[@"code"] ?: @"";
self.possessor.text = item[@"possessor"] ?: @"";
NSString *possessor = item[@"possessor"] ?: @"";
self.iconView.image = [self iconForPossessor:possessor];
}
@end
@interface TransactionItemCell : UITableViewCell
@property (nonatomic, strong) UIView *cardView;
@property (nonatomic, strong) UIImageView *statusIcon;
@property (nonatomic, strong) UILabel *statusLabel;
@property (nonatomic, strong) UILabel *codeLabel;
@property (nonatomic, strong) UILabel *dateLabel;
- (void)configureWithItem:(NSDictionary *)item;
@end
@implementation TransactionItemCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (!self) return nil;
self.selectionStyle = UITableViewCellSelectionStyleNone;
self.backgroundColor = UIColor.clearColor;
// Card container
self.cardView = [[UIView alloc] init];
self.cardView.translatesAutoresizingMaskIntoConstraints = NO;
self.cardView.backgroundColor = UIColor.whiteColor;
self.cardView.layer.cornerRadius = 12;
self.cardView.layer.masksToBounds = NO;
self.cardView.layer.shadowColor = [UIColor blackColor].CGColor;
self.cardView.layer.shadowOpacity = 0.05;
self.cardView.layer.shadowRadius = 4;
self.cardView.layer.shadowOffset = CGSizeMake(0, 2);
[self.contentView addSubview:self.cardView];
// Status icon
self.statusIcon = [[UIImageView alloc] init];
self.statusIcon.translatesAutoresizingMaskIntoConstraints = NO;
self.statusIcon.contentMode = UIViewContentModeScaleAspectFit;
[self.cardView addSubview:self.statusIcon];
// Status label
self.statusLabel = [[UILabel alloc] init];
self.statusLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.statusLabel.font = [UIFont boldSystemFontOfSize:16];
self.statusLabel.textColor = UIColor.darkGrayColor;
self.statusLabel.numberOfLines = 0;
self.statusLabel.lineBreakMode = NSLineBreakByWordWrapping;
[self.cardView addSubview:self.statusLabel];
// Code label
self.codeLabel = [[UILabel alloc] init];
self.codeLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.codeLabel.font = [UIFont systemFontOfSize:14];
self.codeLabel.numberOfLines = 0;
self.codeLabel.lineBreakMode = NSLineBreakByWordWrapping;
[self.cardView addSubview:self.codeLabel];
// Date label
self.dateLabel = [[UILabel alloc] init];
self.dateLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.dateLabel.font = [UIFont italicSystemFontOfSize:14];
self.dateLabel.textColor = UIColor.grayColor;
self.dateLabel.numberOfLines = 0;
self.dateLabel.lineBreakMode = NSLineBreakByWordWrapping;
[self.cardView addSubview:self.dateLabel];
[self setupConstraints];
return self;
}
- (void)setupConstraints {
CGFloat padding = 12.0;
[NSLayoutConstraint activateConstraints:@[
// CardView edges
[self.cardView.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:padding],
[self.cardView.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor constant:-padding],
[self.cardView.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
[self.cardView.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-16],
// Status icon
[self.statusIcon.leadingAnchor constraintEqualToAnchor:self.cardView.leadingAnchor constant:padding],
[self.statusIcon.topAnchor constraintEqualToAnchor:self.cardView.topAnchor constant:padding],
[self.statusIcon.widthAnchor constraintEqualToConstant:28],
[self.statusIcon.heightAnchor constraintEqualToConstant:28],
// Status label
[self.statusLabel.leadingAnchor constraintEqualToAnchor:self.statusIcon.trailingAnchor constant:padding],
[self.statusLabel.trailingAnchor constraintEqualToAnchor:self.cardView.trailingAnchor constant:-padding],
[self.statusLabel.topAnchor constraintEqualToAnchor:self.cardView.topAnchor constant:padding],
// Code label
[self.codeLabel.leadingAnchor constraintEqualToAnchor:self.statusLabel.leadingAnchor],
[self.codeLabel.trailingAnchor constraintEqualToAnchor:self.statusLabel.trailingAnchor],
[self.codeLabel.topAnchor constraintEqualToAnchor:self.statusLabel.bottomAnchor constant:4],
// Date label
[self.dateLabel.leadingAnchor constraintEqualToAnchor:self.statusLabel.leadingAnchor],
[self.dateLabel.trailingAnchor constraintEqualToAnchor:self.statusLabel.trailingAnchor],
[self.dateLabel.topAnchor constraintEqualToAnchor:self.codeLabel.bottomAnchor constant:4],
[self.dateLabel.bottomAnchor constraintEqualToAnchor:self.cardView.bottomAnchor constant:-padding],
]];
}
- (UIImage *)iconForStatus:(NSString *)status {
if ([status.lowercaseString containsString:@"approved"]) {
return [UIImage imageNamed:@"icon_success"];
}
if ([status.lowercaseString containsString:@"pending"]) {
return [UIImage imageNamed:@"icon_pending"];
}
if ([status.lowercaseString containsString:@"rectification"]) {
return [UIImage imageNamed:@"icon_calendar"];
}
return [UIImage imageNamed:@"icon_default"];
}
- (void)configureWithItem:(NSDictionary *)item {
self.statusLabel.text = item[@"status"] ?: @"";
self.codeLabel.text = item[@"code"] ?: @"";
NSString *rawDate = item[@"created_at"];
self.dateLabel.text = [self formattedDateFromString:rawDate] ?: @"";
NSString *status = item[@"status"] ?: @"";
self.statusIcon.image = [self iconForStatus:status];
}
- (NSString *)formattedDateFromString:(NSString *)dateString {
// 1. Input formatter matches your API format
NSDateFormatter *inputFormatter = [[NSDateFormatter alloc] init];
inputFormatter.dateFormat = @"yyyy-MM-dd HH:mm:ss";
inputFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]; // ensures consistent parsing
NSDate *date = [inputFormatter dateFromString:dateString];
if (!date) return dateString; // fallback if parsing fails
// 2. Output formatter for desired display
NSDateFormatter *outputFormatter = [[NSDateFormatter alloc] init];
outputFormatter.dateFormat = @"dd MMM yyyy h:mm a";
outputFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US"];
return [outputFormatter stringFromDate:date];
}
@end
@interface AccessItemViewController () <UITableViewDelegate, UITableViewDataSource>
@property (nonatomic, strong) UIView *headerView;
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UIButton *backButton;
// Main container
@property (nonatomic, strong) UIView *contentContainer;
@property (nonatomic, strong) UITableView *tableView;
// API
@property (nonatomic, strong) NSString *termsName;
@property (nonatomic, strong) NSString *termsContent;
@end
@implementation AccessItemViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self fetchAccessItem];
self.view.backgroundColor = UIColor.whiteColor;
[self setupHeader];
[self setupMainContainer];
[self setupTable];
}
#pragma mark - Header
- (void)setupHeader{
self.headerView = [[UIView alloc] init];
self.headerView.backgroundColor = [UIColor colorWithRed:0.0 green:0.45 blue:0.55 alpha:1];
self.headerView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.headerView];
self.titleLabel = [[UILabel alloc] init];
self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.titleLabel.textAlignment = NSTextAlignmentCenter;
self.titleLabel.textColor = UIColor.whiteColor;
self.titleLabel.font = [UIFont boldSystemFontOfSize:18];
self.titleLabel.text = @"Access Item";
[self.headerView addSubview:self.titleLabel];
self.backButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.backButton.translatesAutoresizingMaskIntoConstraints = NO;
[self.backButton setImage:[UIImage systemImageNamed:@"chevron.backward"]
forState:UIControlStateNormal];
[self.backButton addTarget:self
action:@selector(onBack)
forControlEvents:UIControlEventTouchUpInside];
self.backButton.tintColor = UIColor.whiteColor;
[self.headerView addSubview:self.backButton];
[NSLayoutConstraint activateConstraints:@[
[self.headerView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor],
[self.headerView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.headerView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.headerView.heightAnchor constraintEqualToConstant:48],
[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],
]];
}
#pragma mark - Container
- (void)setupMainContainer{
self.contentContainer = [[UIView alloc] init];
self.contentContainer.translatesAutoresizingMaskIntoConstraints = NO;
self.contentContainer.backgroundColor = [UIColor colorWithWhite:0.96 alpha:1];
[self.view addSubview:self.contentContainer];
[NSLayoutConstraint activateConstraints:@[
[self.contentContainer.topAnchor constraintEqualToAnchor:self.headerView.bottomAnchor],
[self.contentContainer.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.contentContainer.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.contentContainer.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor]
]];
}
#pragma mark - Setup Table
- (void)setupTable {
self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];
self.tableView.translatesAutoresizingMaskIntoConstraints = NO;
self.tableView.delegate = self;
self.tableView.dataSource = self;
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 80;
[self.tableView registerClass:[SubmittedItemCell class] forCellReuseIdentifier:@"SubmittedItemCell"];
[self.tableView registerClass:[TransactionItemCell class] forCellReuseIdentifier:@"TransactionItemCell"];
[self.view addSubview:self.tableView];
[NSLayoutConstraint activateConstraints:@[
[self.tableView.topAnchor constraintEqualToAnchor:self.headerView.bottomAnchor],
[self.tableView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.tableView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.tableView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor]
]];
}
#pragma mark - Api
- (void)fetchAccessItem{
[AccessItemAPIClient fetchAccessItem:@"135"
completion:^(BOOL success, NSDictionary *data, NSError *error) {
NSLog(@"📦 Received General Info Data: %@", data);
NSDictionary *general = data[@"Data"];
// 1️⃣ Write to file for debugging (your existing logic)
NSString *plainText = [NSString stringWithFormat:@"%@", data];
NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString *filePath = [docsPath stringByAppendingPathComponent:@"generalData.txt"];
[plainText writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
NSLog(@"📁 appointData saved as plain text to: %@", filePath);
NSDictionary *accessItem = data[@"Data"];
self.termsName = accessItem[@"termsCondition_name"] ?: @"";
self.termsContent = accessItem[@"termsCondition_content"] ?: @"";
self.submittedItems = accessItem[@"item_submitted"] ?: @[];
self.transactionItems = accessItem[@"item_transaction"] ?: @[];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
}];
}
#pragma mark - Helpers
- (void)onBack {
[self dismissViewControllerAnimated:YES completion:nil];
}
#pragma mark - TableView
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section == 0) return self.submittedItems.count;
return self.transactionItems.count;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 2;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0) {
SubmittedItemCell *cell =
[tableView dequeueReusableCellWithIdentifier:@"SubmittedItemCell" forIndexPath:indexPath];
[cell configureWithItem:self.submittedItems[indexPath.row]];
return cell;
}
TransactionItemCell *cell =
[tableView dequeueReusableCellWithIdentifier:@"TransactionItemCell" forIndexPath:indexPath];
[cell configureWithItem:self.transactionItems[indexPath.row]];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 1) {
NSDictionary *item = self.transactionItems[indexPath.row];
if ([item[@"status"] isEqualToString:@"Rectification Appointment"]) {
AccessAppointmentViewController *vc = [[AccessAppointmentViewController alloc] init];
vc.appointmentData = item;
vc.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:vc animated:YES completion:nil];
} else {
AccessTransactionViewController *vc = [[AccessTransactionViewController alloc] init];
vc.transactionData = item;
vc.unitID = self.unitID;
vc.termsName = self.termsName;
vc.termsContent = self.termsContent;
vc.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:vc animated:YES completion:nil];
}
}
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return (section == 0) ? @"Submitted Items" : @"Transaction";
}
@end
// AccessTransactionViewController.h
#import <UIKit/UIKit.h>
@interface AccessTransactionViewController : UIViewController
@property (nonatomic, strong) NSDictionary *transactionData;
@property (nonatomic, strong) NSArray *items;
@property (nonatomic, strong) NSString *termsName;
@property (nonatomic, strong) NSString *termsContent;
@property (nonatomic, strong) NSString *unitID;
@end
// AccessTransactionViewController.mm
#import "AccessTransactionViewController.h"
#import <WebKit/WebKit.h>
@interface AccessTransactionViewController () <UITableViewDelegate, UITableViewDataSource>
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UIView *contentView;
@property (nonatomic, strong) UIView *header;
// Sections
@property (nonatomic, strong) UIView *detailsCard;
@property (nonatomic, strong) UITableView *itemsTable;
@property (nonatomic, strong) UILabel *tncTitleLabel;
@property (nonatomic, strong) WKWebView *htmlView;
@property (nonatomic, strong) UILabel *remarksTitle;
@property (nonatomic, strong) UILabel *remarksText;
@property (nonatomic, strong) NSLayoutConstraint *itemsTableHeightConstraint;
@end
@implementation AccessTransactionViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = UIColor.whiteColor;
[self setupHeader];
[self setupScrollView];
[self setupDetailsCard];
[self setupItemsTable];
[self setupTermsSection];
[self setupRemarksSection];
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
[self updateItemsTableHeight];
}
#pragma mark - Header
- (void)setupHeader {
self.header = [[UIView alloc] init];
self.header.translatesAutoresizingMaskIntoConstraints = NO;
self.header.backgroundColor = [UIColor colorWithRed:0 green:0.45 blue:0.55 alpha:1];
[self.view addSubview:self.header];
UILabel *titleLabel = [[UILabel alloc] init];
titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
titleLabel.textColor = UIColor.whiteColor;
titleLabel.font = [UIFont boldSystemFontOfSize:18];
titleLabel.text = @"Transaction Details"; // or Appointment Details
[self.header addSubview:titleLabel];
UIButton *backBtn = [UIButton buttonWithType:UIButtonTypeSystem];
backBtn.translatesAutoresizingMaskIntoConstraints = NO;
[backBtn setImage:[UIImage systemImageNamed:@"chevron.backward"] forState:UIControlStateNormal];
backBtn.tintColor = UIColor.whiteColor;
[backBtn addTarget:self action:@selector(onBack) forControlEvents:UIControlEventTouchUpInside];
[self.header addSubview:backBtn];
[NSLayoutConstraint activateConstraints:@[
[self.header.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor],
[self.header.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.header.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.header.heightAnchor constraintEqualToConstant:48],
[backBtn.leadingAnchor constraintEqualToAnchor:self.header.leadingAnchor constant:12],
[backBtn.centerYAnchor constraintEqualToAnchor:self.header.centerYAnchor],
[titleLabel.centerXAnchor constraintEqualToAnchor:self.header.centerXAnchor],
[titleLabel.centerYAnchor constraintEqualToAnchor:self.header.centerYAnchor],
]];
}
#pragma mark - Scroll View
- (void)setupScrollView {
self.scrollView = [[UIScrollView alloc] init];
self.scrollView.translatesAutoresizingMaskIntoConstraints = NO;
self.contentView = [[UIView alloc] init];
self.contentView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.scrollView];
[self.scrollView addSubview:self.contentView];
[NSLayoutConstraint activateConstraints:@[
[self.scrollView.topAnchor constraintEqualToAnchor:self.header.bottomAnchor constant:10],
[self.scrollView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[self.scrollView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[self.scrollView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor],
[self.contentView.topAnchor constraintEqualToAnchor:self.scrollView.topAnchor],
[self.contentView.leadingAnchor constraintEqualToAnchor:self.scrollView.leadingAnchor],
[self.contentView.trailingAnchor constraintEqualToAnchor:self.scrollView.trailingAnchor],
[self.contentView.bottomAnchor constraintEqualToAnchor:self.scrollView.bottomAnchor],
[self.contentView.widthAnchor constraintEqualToAnchor:self.scrollView.widthAnchor]
]];
}
#pragma mark - Details Card
- (void)setupDetailsCard {
// Title outside the card
UILabel *title = [self bold18:@"Details"];
[self.contentView addSubview:title];
[NSLayoutConstraint activateConstraints:@[
[title.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:10],
[title.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
[title.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-16],
]];
// Card
UIView *card = [[UIView alloc] init];
card.translatesAutoresizingMaskIntoConstraints = NO;
card.backgroundColor = UIColor.whiteColor;
card.layer.cornerRadius = 12;
card.layer.shadowOpacity = 0.1;
card.layer.shadowRadius = 4;
card.layer.shadowOffset = CGSizeMake(0,2);
[self.contentView addSubview:card];
UILabel *unitNoLabel = [self regular16:[NSString stringWithFormat:@"Unit No: %@", self.unitID ?: @"--"]];
UILabel *unitOwnerLabel = [self regular16:[NSString stringWithFormat:@"Unit Owner: %@", self.transactionData[@"owner_name"] ?: @"--"]];
[card addSubview:unitNoLabel];
[card addSubview:unitOwnerLabel];
[NSLayoutConstraint activateConstraints:@[
[card.topAnchor constraintEqualToAnchor:title.bottomAnchor constant:8],
[card.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
[card.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-16],
[unitNoLabel.topAnchor constraintEqualToAnchor:card.topAnchor constant:16],
[unitNoLabel.leadingAnchor constraintEqualToAnchor:card.leadingAnchor constant:16],
[unitNoLabel.trailingAnchor constraintEqualToAnchor:card.trailingAnchor constant:-16],
[unitOwnerLabel.topAnchor constraintEqualToAnchor:unitNoLabel.bottomAnchor constant:8],
[unitOwnerLabel.leadingAnchor constraintEqualToAnchor:card.leadingAnchor constant:16],
[unitOwnerLabel.trailingAnchor constraintEqualToAnchor:card.trailingAnchor constant:-16],
[unitOwnerLabel.bottomAnchor constraintEqualToAnchor:card.bottomAnchor constant:-16]
]];
self.detailsCard = card;
}
#pragma mark - Items Table
- (void)setupItemsTable {
// Title
UILabel *itemsTitle = [[UILabel alloc] init];
itemsTitle.translatesAutoresizingMaskIntoConstraints = NO;
itemsTitle.font = [UIFont boldSystemFontOfSize:18];
itemsTitle.text = @"Items";
[self.contentView addSubview:itemsTitle];
// Table
self.itemsTable = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
self.itemsTable.translatesAutoresizingMaskIntoConstraints = NO;
self.itemsTable.delegate = self;
self.itemsTable.dataSource = self;
self.itemsTable.scrollEnabled = NO; // let table expand naturally
self.itemsTable.estimatedRowHeight = 44;
self.itemsTable.rowHeight = UITableViewAutomaticDimension;
self.itemsTable.separatorStyle = UITableViewCellSeparatorStyleNone; // we handle separators manually
[self.contentView addSubview:self.itemsTable];
// Table header
UIView *header = [self createTableHeader];
self.itemsTable.tableHeaderView = header;
[header layoutIfNeeded];
CGRect f = header.frame;
f.size.height = [header systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
header.frame = f;
self.itemsTable.tableHeaderView = header;
// Layout
[NSLayoutConstraint activateConstraints:@[
[itemsTitle.topAnchor constraintEqualToAnchor:self.detailsCard.bottomAnchor constant:20],
[itemsTitle.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
[self.itemsTable.topAnchor constraintEqualToAnchor:itemsTitle.bottomAnchor constant:8],
[self.itemsTable.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
[self.itemsTable.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-16],
// [self.itemsTable.bottomAnchor constraintEqualToAnchor:self.tncTitleLabel.topAnchor constant:-20], // let scrollview content size determine
]];
self.itemsTableHeightConstraint =
[self.itemsTable.heightAnchor constraintEqualToConstant:10];
self.itemsTableHeightConstraint.active = YES;
}
- (UIView *)createTableHeader {
CGFloat headerHeight = 40;
NSArray *titles = @[@"No.", @"Item", @"Possession", @"Qty."];
CGFloat flexes[] = {0.7, 1.3, 1.3, 0.7}; // React Native style
UIView *header = [[UIView alloc] init];
header.backgroundColor = UIColor.blackColor;
header.translatesAutoresizingMaskIntoConstraints = NO;
UILabel *prev = nil;
CGFloat totalFlex = 0.7 + 1.3 + 1.3 + 0.7;
for (int i = 0; i < titles.count; i++) {
UILabel *lbl = [self createHeaderLabel:titles[i]];
[header addSubview:lbl];
lbl.translatesAutoresizingMaskIntoConstraints = NO;
[NSLayoutConstraint activateConstraints:@[
[lbl.topAnchor constraintEqualToAnchor:header.topAnchor constant:12],
[lbl.bottomAnchor constraintEqualToAnchor:header.bottomAnchor constant:-12],
[lbl.widthAnchor constraintEqualToAnchor:header.widthAnchor multiplier:flexes[i]/totalFlex]
]];
if (prev) {
[lbl.leadingAnchor constraintEqualToAnchor:prev.trailingAnchor].active = YES;
} else {
[lbl.leadingAnchor constraintEqualToAnchor:header.leadingAnchor].active = YES;
}
prev = lbl;
// separator
if (i < titles.count - 1) {
UIView *sep = [[UIView alloc] init];
sep.backgroundColor = [UIColor colorWithWhite:0.9 alpha:1.0];
sep.translatesAutoresizingMaskIntoConstraints = NO;
[header addSubview:sep];
[NSLayoutConstraint activateConstraints:@[
[sep.widthAnchor constraintEqualToConstant:0.5],
[sep.topAnchor constraintEqualToAnchor:header.topAnchor constant:12],
[sep.bottomAnchor constraintEqualToAnchor:header.bottomAnchor constant:-12],
[sep.leadingAnchor constraintEqualToAnchor:lbl.trailingAnchor]
]];
}
}
// Force intrinsic height
[header.heightAnchor constraintEqualToConstant:headerHeight].active = YES;
return header;
}
- (UILabel *)createHeaderLabel:(NSString *)text {
UILabel *lbl = [[UILabel alloc] init];
lbl.text = text;
lbl.font = [UIFont boldSystemFontOfSize:14];
lbl.textColor = UIColor.whiteColor;
lbl.textAlignment = NSTextAlignmentCenter;
return lbl;
}
- (void)updateItemsTableHeight {
[self.itemsTable layoutIfNeeded];
CGFloat height = self.itemsTable.contentSize.height;
self.itemsTableHeightConstraint.constant = height;
[self.view layoutIfNeeded];
}
#pragma mark - Terms Section
- (void)setupTermsSection {
self.tncTitleLabel = [[UILabel alloc] init];
self.tncTitleLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.tncTitleLabel.font = [UIFont boldSystemFontOfSize:18];
self.tncTitleLabel.text = @"Terms & Conditions";
[self.contentView addSubview:self.tncTitleLabel];
self.htmlView = [[WKWebView alloc] init];
self.htmlView.translatesAutoresizingMaskIntoConstraints = NO;
self.htmlView.scrollView.scrollEnabled = NO; // disable internal scrolling
self.htmlView.navigationDelegate = (id<WKNavigationDelegate>)self; // set delegate for dynamic height
[self.contentView addSubview:self.htmlView];
[NSLayoutConstraint activateConstraints:@[
[self.tncTitleLabel.topAnchor constraintEqualToAnchor:self.itemsTable.bottomAnchor constant:20],
[self.tncTitleLabel.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
[self.htmlView.topAnchor constraintEqualToAnchor:self.tncTitleLabel.bottomAnchor constant:8],
[self.htmlView.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
[self.htmlView.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-16],
// initial height, will update dynamically
[self.htmlView.heightAnchor constraintEqualToConstant:100]
]];
// Load styled HTML
if (self.termsContent && self.termsContent.length > 0) {
NSString *styledHTML = [NSString stringWithFormat:
@"<html>"
"<head>"
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0\">"
"<style>"
"body { font-size: 14px; font-family: -apple-system; line-height: 1.5; padding: 12px; background-color: #F9F9F9; }"
"p { margin-bottom: 12px; }"
"</style>"
"</head>"
"<body>%@</body>"
"</html>", self.termsContent];
[self.htmlView loadHTMLString:styledHTML baseURL:nil];
}
}
#pragma mark - WKNavigationDelegate
// Adjust webview height dynamically after content loads
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
[webView evaluateJavaScript:@"document.body.scrollHeight;" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
if (!error && result) {
CGFloat height = [result doubleValue];
for (NSLayoutConstraint *constraint in webView.constraints) {
if (constraint.firstAttribute == NSLayoutAttributeHeight) {
constraint.constant = height;
[UIView animateWithDuration:0.25 animations:^{
[self.view layoutIfNeeded];
}];
break;
}
}
}
}];
}
#pragma mark - Remarks Section
- (void)setupRemarksSection {
// --- Remarks Title ---
self.remarksTitle = [self bold18:@"Remarks"];
[self.contentView addSubview:self.remarksTitle];
// --- Remarks Text ---
self.remarksText = [[UILabel alloc] init];
self.remarksText.translatesAutoresizingMaskIntoConstraints = NO;
self.remarksText.font = [UIFont systemFontOfSize:15];
self.remarksText.numberOfLines = 0;
self.remarksText.text = self.transactionData[@"remarks"] ?: @"--";
[self.contentView addSubview:self.remarksText];
// --- Submitted By ---
UILabel *submittedTitle = [self bold18:@"Submitted By"];
[self.contentView addSubview:submittedTitle];
UIImageView *submittedSignature = [[UIImageView alloc] init];
submittedSignature.translatesAutoresizingMaskIntoConstraints = NO;
submittedSignature.contentMode = UIViewContentModeScaleAspectFit;
submittedSignature.clipsToBounds = YES;
NSURL *submittedURL = [NSURL URLWithString:self.transactionData[@"signature_submit"]];
if (submittedURL) {
// Simple async load
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *data = [NSData dataWithContentsOfURL:submittedURL];
if (data) {
UIImage *img = [UIImage imageWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
submittedSignature.image = img;
});
}
});
}
[self.contentView addSubview:submittedSignature];
UILabel *submittedName = [self regular16:[NSString stringWithFormat:@"Name: %@", self.transactionData[@"name_submit"] ?: @"--"]];
[self.contentView addSubview:submittedName];
UILabel *submittedDate = [self regular16:[NSString stringWithFormat:@"Date: %@", self.transactionData[@"signature_submit_datetime"] ?: @"--"]];
[self.contentView addSubview:submittedDate];
// --- Received By ---
UILabel *receivedTitle = [self bold18:@"Received By"];
[self.contentView addSubview:receivedTitle];
UIImageView *receivedSignature = [[UIImageView alloc] init];
receivedSignature.translatesAutoresizingMaskIntoConstraints = NO;
receivedSignature.contentMode = UIViewContentModeScaleAspectFit;
receivedSignature.clipsToBounds = YES;
NSURL *receivedURL = [NSURL URLWithString:self.transactionData[@"signature_receive"]];
if (receivedURL) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *data = [NSData dataWithContentsOfURL:receivedURL];
if (data) {
UIImage *img = [UIImage imageWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
receivedSignature.image = img;
});
}
});
}
[self.contentView addSubview:receivedSignature];
UILabel *receivedName = [self regular16:[NSString stringWithFormat:@"Name: %@", self.transactionData[@"name_receive"] ?: @"--"]];
[self.contentView addSubview:receivedName];
UILabel *receivedDate = [self regular16:[NSString stringWithFormat:@"Date: %@", self.transactionData[@"signature_receive_datetime"] ?: @"--"]];
[self.contentView addSubview:receivedDate];
// --- Constraints ---
CGFloat spacing = 8;
[NSLayoutConstraint activateConstraints:@[
// Remarks
[self.remarksTitle.topAnchor constraintEqualToAnchor:self.htmlView.bottomAnchor constant:10],
[self.remarksTitle.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
[self.remarksText.topAnchor constraintEqualToAnchor:self.remarksTitle.bottomAnchor constant:spacing],
[self.remarksText.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
[self.remarksText.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-16],
// Submitted By
[submittedTitle.topAnchor constraintEqualToAnchor:self.remarksText.bottomAnchor constant:spacing*2],
[submittedTitle.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
[submittedSignature.topAnchor constraintEqualToAnchor:submittedTitle.bottomAnchor constant:spacing],
[submittedSignature.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
[submittedSignature.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-16],
[submittedSignature.heightAnchor constraintEqualToConstant:180],
[submittedName.topAnchor constraintEqualToAnchor:submittedSignature.bottomAnchor constant:spacing],
[submittedName.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
[submittedDate.topAnchor constraintEqualToAnchor:submittedName.bottomAnchor constant:spacing],
[submittedDate.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
// Received By
[receivedTitle.topAnchor constraintEqualToAnchor:submittedDate.bottomAnchor constant:spacing*2],
[receivedTitle.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
[receivedSignature.topAnchor constraintEqualToAnchor:receivedTitle.bottomAnchor constant:spacing],
[receivedSignature.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
[receivedSignature.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-16],
[receivedSignature.heightAnchor constraintEqualToConstant:180],
[receivedName.topAnchor constraintEqualToAnchor:receivedSignature.bottomAnchor constant:spacing],
[receivedName.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
[receivedDate.topAnchor constraintEqualToAnchor:receivedName.bottomAnchor constant:spacing],
[receivedDate.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
[receivedDate.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor constant:-40]
]];
}
#pragma mark - Table
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSArray *items = self.transactionData[@"items"];
return items.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellID = @"TransactionItemCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
}
// Clear previous content
for (UIView *v in cell.contentView.subviews) [v removeFromSuperview];
NSDictionary *item = self.transactionData[@"items"][indexPath.row];
UIView *container = [[UIView alloc] init];
container.translatesAutoresizingMaskIntoConstraints = NO;
[cell.contentView addSubview:container];
[NSLayoutConstraint activateConstraints:@[
[container.topAnchor constraintEqualToAnchor:cell.contentView.topAnchor],
[container.leadingAnchor constraintEqualToAnchor:cell.contentView.leadingAnchor],
[container.trailingAnchor constraintEqualToAnchor:cell.contentView.trailingAnchor],
[container.bottomAnchor constraintEqualToAnchor:cell.contentView.bottomAnchor]
]];
// Columns
NSArray *texts = @[
[NSString stringWithFormat:@"%ld", indexPath.row+1],
item[@"name"] ?: @"--",
self.transactionData[@"possession"] ?: @"--",
[NSString stringWithFormat:@"%@", item[@"quantity"] ?: @"0"]
];
CGFloat flexes[] = {0.7, 1.3, 1.3, 0.7};
CGFloat totalFlex = 0.7+1.3+1.3+0.7;
UILabel *prev = nil;
for (int i = 0; i < texts.count; i++) {
UILabel *col = [self createCellLabel:texts[i]];
col.textAlignment = NSTextAlignmentCenter;
[container addSubview:col];
col.translatesAutoresizingMaskIntoConstraints = NO;
col.adjustsFontSizeToFitWidth = YES;
col.minimumScaleFactor = 0.5;
[NSLayoutConstraint activateConstraints:@[
[col.topAnchor constraintEqualToAnchor:container.topAnchor constant:12],
[col.bottomAnchor constraintEqualToAnchor:container.bottomAnchor constant:-12],
[col.widthAnchor constraintEqualToAnchor:container.widthAnchor multiplier:flexes[i]/totalFlex]
]];
if (prev) {
[col.leadingAnchor constraintEqualToAnchor:prev.trailingAnchor].active = YES;
} else {
[col.leadingAnchor constraintEqualToAnchor:container.leadingAnchor].active = YES;
}
prev = col;
// separator
if (i < texts.count - 1) {
UIView *sep = [[UIView alloc] init];
sep.backgroundColor = [UIColor colorWithWhite:0.9 alpha:1.0];
sep.translatesAutoresizingMaskIntoConstraints = NO;
[container addSubview:sep];
[NSLayoutConstraint activateConstraints:@[
[sep.widthAnchor constraintEqualToConstant:0.5],
[sep.topAnchor constraintEqualToAnchor:container.topAnchor constant:12],
[sep.bottomAnchor constraintEqualToAnchor:container.bottomAnchor constant:-12],
[sep.leadingAnchor constraintEqualToAnchor:col.trailingAnchor]
]];
}
}
return cell;
}
#pragma mark - Helpers
- (void)onBack {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (UILabel *)bold18:(NSString *)text {
UILabel *lbl = [[UILabel alloc] init];
lbl.translatesAutoresizingMaskIntoConstraints = NO;
lbl.font = [UIFont boldSystemFontOfSize:18];
lbl.text = text;
return lbl;
}
- (UILabel *)regular16:(NSString *)text {
UILabel *lbl = [[UILabel alloc] init];
lbl.translatesAutoresizingMaskIntoConstraints = NO;
lbl.font = [UIFont systemFontOfSize:16];
lbl.textColor = UIColor.darkGrayColor;
lbl.text = text;
return lbl;
}
- (NSString *)formattedDate:(NSString *)dateStr {
NSDateFormatter *df = [[NSDateFormatter alloc] init];
df.dateFormat = @"yyyy-MM-dd HH:mm:ss";
NSDate *date = [df dateFromString:dateStr];
if (!date) return dateStr;
NSDateFormatter *output = [[NSDateFormatter alloc] init];
output.dateFormat = @"dd MMM yyyy h:mm a";
return [output stringFromDate:date];
}
- (UILabel *)createCellLabel:(NSString *)text {
UILabel *lbl = [[UILabel alloc] init];
lbl.font = [UIFont systemFontOfSize:15];
lbl.numberOfLines = 0;
lbl.lineBreakMode = NSLineBreakByWordWrapping;
lbl.text = text;
return lbl;
}
@end
...@@ -58,8 +58,6 @@ ...@@ -58,8 +58,6 @@
// Log the path so you can find it // Log the path so you can find it
NSLog(@"📁 issueData saved as plain text to: %@", filePath); NSLog(@"📁 issueData saved as plain text to: %@", filePath);
NSDictionary *locData = self.locationData; NSDictionary *locData = self.locationData;
if ([locData isKindOfClass:[NSDictionary class]]) { if ([locData isKindOfClass:[NSDictionary class]]) {
self.categories = locData[@"category"]; self.categories = locData[@"category"];
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#import "AppointmentDetailsViewController.h" #import "AppointmentDetailsViewController.h"
#import "AppointmentViewMoreViewController.h" #import "AppointmentViewMoreViewController.h"
#import "GeneralInfoViewController.h" #import "GeneralInfoViewController.h"
#import "AccessItemViewController.h"
@interface DashboardViewController () @interface DashboardViewController ()
...@@ -342,6 +343,11 @@ ...@@ -342,6 +343,11 @@
} }
case 2: { case 2: {
NSLog(@"Navigating to Access Item"); NSLog(@"Navigating to Access Item");
AccessItemViewController *nextVC = [[AccessItemViewController alloc] init];
nextVC.unitID = self.projectCode;
nextVC.unitName = self.projectName;
nextVC.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:nextVC animated:YES completion:nil];
} }
default: default:
break; break;
......
...@@ -561,9 +561,24 @@ typedef struct { ...@@ -561,9 +561,24 @@ typedef struct {
self.owners = general[@"unit_owner"] ?: @[]; self.owners = general[@"unit_owner"] ?: @[];
self.jointOwners = general[@"joint_unit_owner"] ?: @[]; self.jointOwners = general[@"joint_unit_owner"] ?: @[];
self.unitDocuments = general[@"owner_document_unit"] ?: @[];
self.layoutDocuments = general[@"owner_document_phase"] ?: @[]; self.layoutDocuments = general[@"owner_document_phase"] ?: @[];
self.generalDocuments = general[@"owner_document_project"] ?: @[]; self.generalDocuments = general[@"owner_document_project"] ?: @[];
NSArray *rawUnitDocs = general[@"owner_document_unit"];
NSMutableArray *unitDocs = rawUnitDocs ? [rawUnitDocs mutableCopy] : [NSMutableArray array];
// clearance_letter_attachment is a DICTIONARY
NSDictionary *clearanceDict = general[@"clearance_letter_attachment"];
if (clearanceDict &&
[clearanceDict isKindOfClass:[NSDictionary class]] &&
[clearanceDict[@"file"] isKindOfClass:[NSString class]] &&
[clearanceDict[@"file"] length] > 0)
{
[unitDocs addObject:clearanceDict];
}
self.unitDocuments = unitDocs;
self.forms = general[@"contactless_form"] ?: @[]; self.forms = general[@"contactless_form"] ?: @[];
...@@ -925,7 +940,6 @@ typedef struct { ...@@ -925,7 +940,6 @@ typedef struct {
UIButton *btn = [self collapsibleHeaderWithTitle:title]; UIButton *btn = [self collapsibleHeaderWithTitle:title];
btn.translatesAutoresizingMaskIntoConstraints = NO; btn.translatesAutoresizingMaskIntoConstraints = NO;
[self.documentsContainer addSubview:btn];
UIStackView *stack = [[UIStackView alloc] init]; UIStackView *stack = [[UIStackView alloc] init];
stack.axis = UILayoutConstraintAxisVertical; stack.axis = UILayoutConstraintAxisVertical;
...@@ -937,30 +951,25 @@ typedef struct { ...@@ -937,30 +951,25 @@ typedef struct {
stack.layoutMargins = UIEdgeInsetsMake(12, 12, 12, 12); stack.layoutMargins = UIEdgeInsetsMake(12, 12, 12, 12);
stack.layoutMarginsRelativeArrangement = YES; stack.layoutMarginsRelativeArrangement = YES;
[self.documentsContainer addSubview:stack];
objc_setAssociatedObject(btn, "sectionStack", stack, OBJC_ASSOCIATION_RETAIN); objc_setAssociatedObject(btn, "sectionStack", stack, OBJC_ASSOCIATION_RETAIN);
[btn addTarget:self action:@selector(toggleSection:) forControlEvents:UIControlEventTouchUpInside]; [btn addTarget:self action:@selector(toggleSection:) forControlEvents:UIControlEventTouchUpInside];
UIImageView *arrow = objc_getAssociatedObject(btn, "arrowView"); UIImageView *arrow = objc_getAssociatedObject(btn, "arrowView");
if (arrow) { if (arrow) {
arrow.transform = CGAffineTransformMakeRotation(M_PI); // expanded state (chevron.up) arrow.transform = CGAffineTransformMakeRotation(M_PI);
} }
for (NSDictionary *doc in items) { for (NSDictionary *doc in items) {
NSString *fileURL = doc[@"file"]; NSString *fileURL = doc[@"file"];
NSString *name = doc[@"name"] ?: @"Document"; NSString *name = doc[@"name"] ?: @"Document";
// Card container
UIView *card = [[UIView alloc] init]; UIView *card = [[UIView alloc] init];
card.backgroundColor = UIColor.whiteColor; card.backgroundColor = UIColor.whiteColor;
card.layer.cornerRadius = 8; card.layer.cornerRadius = 8;
card.layer.borderWidth = 0.5; card.layer.borderWidth = 0.5;
card.layer.borderColor = UIColor.lightGrayColor.CGColor; card.layer.borderColor = UIColor.lightGrayColor.CGColor;
card.translatesAutoresizingMaskIntoConstraints = NO; card.translatesAutoresizingMaskIntoConstraints = NO;
// Add label inside card
UILabel *lbl = [[UILabel alloc] init]; UILabel *lbl = [[UILabel alloc] init];
lbl.text = name; lbl.text = name;
lbl.font = [UIFont systemFontOfSize:15]; lbl.font = [UIFont systemFontOfSize:15];
...@@ -968,7 +977,7 @@ typedef struct { ...@@ -968,7 +977,7 @@ typedef struct {
[card addSubview:lbl]; [card addSubview:lbl];
lbl.translatesAutoresizingMaskIntoConstraints = NO; lbl.translatesAutoresizingMaskIntoConstraints = NO;
[NSLayoutConstraint activateConstraints:@[ [NSLayoutConstraint activateConstraints:@[
[lbl.topAnchor constraintEqualToAnchor:card.topAnchor constant:10], [lbl.topAnchor constraintEqualToAnchor:card.topAnchor constant:10],
[lbl.leadingAnchor constraintEqualToAnchor:card.leadingAnchor constant:12], [lbl.leadingAnchor constraintEqualToAnchor:card.leadingAnchor constant:12],
...@@ -976,12 +985,10 @@ typedef struct { ...@@ -976,12 +985,10 @@ typedef struct {
[lbl.bottomAnchor constraintEqualToAnchor:card.bottomAnchor constant:-10], [lbl.bottomAnchor constraintEqualToAnchor:card.bottomAnchor constant:-10],
]]; ]];
// Attach PDF URL to card if ([fileURL length] > 0) {
if (fileURL && ![fileURL isKindOfClass:[NSNull class]] && fileURL.length > 0) {
objc_setAssociatedObject(card, "pdfURL", fileURL, OBJC_ASSOCIATION_RETAIN_NONATOMIC); objc_setAssociatedObject(card, "pdfURL", fileURL, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
objc_setAssociatedObject(card, "pdfName", name, OBJC_ASSOCIATION_RETAIN_NONATOMIC); objc_setAssociatedObject(card, "pdfName", name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
// Add tap gesture
UITapGestureRecognizer *tap = UITapGestureRecognizer *tap =
[[UITapGestureRecognizer alloc] initWithTarget:self [[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(openPDFFromView:)]; action:@selector(openPDFFromView:)];
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<dict> <dict>
<key>Assets.car</key> <key>Assets.car</key>
<data> <data>
mDeq0E4lblXfFuIgkojjE5zY6hk= nz4CVgVrIgti3Z6dGyfqT52lO7E=
</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>
/JZsUWwwr7A+ZF0o001HQXRnzpI= t43yRjSptMFTXQfSxY21jokBVtU=
</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>
0+eonZqFOeyimWUH94CuUhfXNEulhfi9YeuUE/wnX0s= J60ydBHIUa66OEr3jc21333AHp87l+VEFvKU7h3lu2M=
</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>
mDeq0E4lblXfFuIgkojjE5zY6hk= nz4CVgVrIgti3Z6dGyfqT52lO7E=
</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>
4pQwOIuYwsUH4Iiw1M402s3Ii8Y= CSlwpYePP8U03s3cRC5622W7ESM=
</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>
0+eonZqFOeyimWUH94CuUhfXNEulhfi9YeuUE/wnX0s= J60ydBHIUa66OEr3jc21333AHp87l+VEFvKU7h3lu2M=
</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