Commit 33030498 authored by Wei Han's avatar Wei Han

survey done

parent 02bbb1d6
...@@ -22,7 +22,8 @@ ...@@ -22,7 +22,8 @@
@property (nonatomic, assign) BOOL mandatory; @property (nonatomic, assign) BOOL mandatory;
@property (nonatomic, strong) NSArray<NSDictionary *> *ratesChecklist; @property (nonatomic, strong) NSArray<NSDictionary *> *ratesChecklist;
@property (nonatomic, strong) NSMutableDictionary<NSNumber *, id> *answers; @property (nonatomic, strong) NSMutableDictionary<NSNumber *, id> *answers;
@property (nonatomic, assign) NSInteger selectedNPS;
@property (nonatomic, strong) NSDictionary *surveyData;
@end @end
...@@ -32,6 +33,7 @@ ...@@ -32,6 +33,7 @@
self.view.backgroundColor = UIColor.whiteColor; self.view.backgroundColor = UIColor.whiteColor;
self.answers = [NSMutableDictionary dictionary]; self.answers = [NSMutableDictionary dictionary];
self.selectedNPS = -1;
[self setupHeader]; [self setupHeader];
[self setupScrollView]; [self setupScrollView];
[self requestSurvey]; [self requestSurvey];
...@@ -169,7 +171,7 @@ ...@@ -169,7 +171,7 @@
[self.submitButton setTitle:@"Submit" forState:UIControlStateNormal]; [self.submitButton setTitle:@"Submit" forState:UIControlStateNormal];
self.submitButton.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0]; self.submitButton.backgroundColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0];
[self.submitButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal]; [self.submitButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
self.submitButton.layer.cornerRadius = 8; self.submitButton.layer.cornerRadius = 12;
self.submitButton.translatesAutoresizingMaskIntoConstraints = NO; self.submitButton.translatesAutoresizingMaskIntoConstraints = NO;
[self.submitButton addTarget:self action:@selector(onSubmit) forControlEvents:UIControlEventTouchUpInside]; [self.submitButton addTarget:self action:@selector(onSubmit) forControlEvents:UIControlEventTouchUpInside];
[self.contentView addSubview:self.submitButton]; [self.contentView addSubview:self.submitButton];
...@@ -198,10 +200,11 @@ ...@@ -198,10 +200,11 @@
} else if ([type isEqualToString:@"rateNps"]) { } else if ([type isEqualToString:@"rateNps"]) {
return [self buildNPSRating:item]; return [self buildNPSRating:item];
} else { } else {
return [self buildQuestionPlaceholder:item]; return [self buildQuestionPlaceholder:item];
} }
return [self buildQuestionPlaceholder:item];
return [self buildQuestionPlaceholder:item];
} }
- (UIView *)buildStarRating:(NSDictionary *)item { - (UIView *)buildStarRating:(NSDictionary *)item {
...@@ -210,11 +213,7 @@ ...@@ -210,11 +213,7 @@
container.tag = [item[@"id"] integerValue]; container.tag = [item[@"id"] integerValue];
// Question // Question
UILabel *label = [[UILabel alloc] init]; UILabel *label = [self buildQuestionLabel:item];
label.text = item[@"question"];
label.font = [UIFont systemFontOfSize:14 weight:UIFontWeightBold];
label.numberOfLines = 0;
label.translatesAutoresizingMaskIntoConstraints = NO;
[container addSubview:label]; [container addSubview:label];
// Helper // Helper
...@@ -232,29 +231,40 @@ ...@@ -232,29 +231,40 @@
starsContainer.translatesAutoresizingMaskIntoConstraints = NO; starsContainer.translatesAutoresizingMaskIntoConstraints = NO;
[container addSubview:starsContainer]; [container addSubview:starsContainer];
NSInteger rawCount = [item[@"number_of_rates"] integerValue]; NSInteger count = [item[@"number_of_rates"] integerValue];
NSInteger starCount = MIN(rawCount, 5); count = MAX(1, count);
CGFloat size = 32;
CGFloat spacing = 8; CGFloat spacing = 8;
CGFloat size = [self buttonSizeForCount:count spacing:spacing];
NSMutableArray *stars = [NSMutableArray array];
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
for (int i = 1; i <= starCount; i++) { for (int i = 1; i <= count; i++) {
UIButton *star = [UIButton buttonWithType:UIButtonTypeCustom]; UIButton *star = [UIButton buttonWithType:UIButtonTypeCustom];
star.frame = CGRectMake((i - 1) * (size + spacing), 0, size, size);
star.tag = i; star.tag = i;
[star setImage:[UIImage imageNamed:@"star_empty"] forState:UIControlStateNormal]; [star setImage:[UIImage imageNamed:@"star_empty"
inBundle:bundle
compatibleWithTraitCollection:nil]
forState:UIControlStateNormal];
[star addTarget:self [star addTarget:self
action:@selector(onStarTapped:) action:@selector(onStarTapped:)
forControlEvents:UIControlEventTouchUpInside]; forControlEvents:UIControlEventTouchUpInside];
[starsContainer addSubview:star]; [stars addObject:star];
} }
CGFloat totalWidth = starCount * size + (starCount - 1) * spacing; CGFloat height = [self layoutButtons:stars
inContainer:starsContainer
maxPerRow:count
spacing:spacing
buttonSize:size];
CGFloat totalWidth = (size * count) + (spacing * (count - 1));
[starsContainer.widthAnchor constraintEqualToConstant:totalWidth].active = YES; [starsContainer.widthAnchor constraintEqualToConstant:totalWidth].active = YES;
[starsContainer.heightAnchor constraintEqualToConstant:size].active = YES; [starsContainer.heightAnchor constraintEqualToConstant:height].active = YES;
// Constraints // Constraints
[NSLayoutConstraint activateConstraints:@[ [NSLayoutConstraint activateConstraints:@[
...@@ -263,8 +273,8 @@ ...@@ -263,8 +273,8 @@
[label.trailingAnchor constraintEqualToAnchor:container.trailingAnchor], [label.trailingAnchor constraintEqualToAnchor:container.trailingAnchor],
helper.hidden ? helper.hidden ?
[starsContainer.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:8] : [starsContainer.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:12] :
[helper.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:6], [helper.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:12],
[helper.leadingAnchor constraintEqualToAnchor:container.leadingAnchor], [helper.leadingAnchor constraintEqualToAnchor:container.leadingAnchor],
[helper.trailingAnchor constraintEqualToAnchor:container.trailingAnchor], [helper.trailingAnchor constraintEqualToAnchor:container.trailingAnchor],
...@@ -303,10 +313,7 @@ ...@@ -303,10 +313,7 @@
UIView *container = [[UIView alloc] init]; UIView *container = [[UIView alloc] init];
container.translatesAutoresizingMaskIntoConstraints = NO; container.translatesAutoresizingMaskIntoConstraints = NO;
UILabel *label = [[UILabel alloc] init]; UILabel *label = [self buildQuestionLabel:item];
label.text = item[@"question"];
label.font = [UIFont systemFontOfSize:14 weight:UIFontWeightBold];
label.translatesAutoresizingMaskIntoConstraints = NO;
[container addSubview:label]; [container addSubview:label];
UITextField *textField = [[UITextField alloc] init]; UITextField *textField = [[UITextField alloc] init];
...@@ -344,11 +351,7 @@ ...@@ -344,11 +351,7 @@
container.tag = [item[@"id"] integerValue]; container.tag = [item[@"id"] integerValue];
// Question // Question
UILabel *label = [[UILabel alloc] init]; UILabel *label = [self buildQuestionLabel:item];
label.text = item[@"question"];
label.font = [UIFont systemFontOfSize:14 weight:UIFontWeightBold];
label.numberOfLines = 0;
label.translatesAutoresizingMaskIntoConstraints = NO;
[container addSubview:label]; [container addSubview:label];
// Helper // Helper
...@@ -364,42 +367,41 @@ ...@@ -364,42 +367,41 @@
// Buttons container // Buttons container
UIView *buttonsContainer = [[UIView alloc] init]; UIView *buttonsContainer = [[UIView alloc] init];
buttonsContainer.translatesAutoresizingMaskIntoConstraints = NO; buttonsContainer.translatesAutoresizingMaskIntoConstraints = NO;
[container addSubview:buttonsContainer]; [container addSubview:buttonsContainer];
CGFloat size = 36; NSInteger count = [item[@"number_of_rates"] integerValue];
CGFloat spacing = 8; CGFloat spacing = 6;
CGFloat size = [self buttonSizeForCount:MIN(count, 8) spacing:spacing];
NSInteger value = 0; NSMutableArray *buttons = [NSMutableArray array];
CGFloat x = 0;
CGFloat y = 0;
for (int i = 0; i <= 10; i++) { for (int i = 0; i < count; i++) {
// Wrap after 8 → row 2 (9,10) UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem];
if (i == 9) { btn.tag = i;
x = 0;
y += size + spacing;
}
UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem]; btn.layer.cornerRadius = 6;
btn.frame = CGRectMake(x, y, size, size); btn.layer.borderWidth = 1;
btn.tag = i; btn.layer.borderColor = UIColor.lightGrayColor.CGColor;
btn.layer.cornerRadius = 6;
btn.backgroundColor = [self npsColorForValue:i selected:NO];
[btn setTitle:[NSString stringWithFormat:@"%d", i] forState:UIControlStateNormal]; [btn setTitle:[NSString stringWithFormat:@"%d", i]
[btn setTitleColor:UIColor.blackColor forState:UIControlStateNormal]; forState:UIControlStateNormal];
[btn setTitleColor:UIColor.blackColor forState:UIControlStateNormal];
[btn addTarget:self [btn addTarget:self
action:@selector(onNPSTapped:) action:@selector(onNPSTapped:)
forControlEvents:UIControlEventTouchUpInside]; forControlEvents:UIControlEventTouchUpInside];
[buttonsContainer addSubview:btn]; [buttons addObject:btn];
}
x += size + spacing; CGFloat height = [self layoutButtons:buttons
} inContainer:buttonsContainer
maxPerRow:8
spacing:spacing
buttonSize:size];
CGFloat totalHeight = y + size; [buttonsContainer.heightAnchor constraintEqualToConstant:height].active = YES;
[buttonsContainer.heightAnchor constraintEqualToConstant:totalHeight].active = YES;
// Constraints // Constraints
[NSLayoutConstraint activateConstraints:@[ [NSLayoutConstraint activateConstraints:@[
...@@ -409,7 +411,7 @@ ...@@ -409,7 +411,7 @@
helper.hidden ? helper.hidden ?
[buttonsContainer.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:8] : [buttonsContainer.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:8] :
[helper.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:6], [helper.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:12],
[helper.leadingAnchor constraintEqualToAnchor:container.leadingAnchor], [helper.leadingAnchor constraintEqualToAnchor:container.leadingAnchor],
[helper.trailingAnchor constraintEqualToAnchor:container.trailingAnchor], [helper.trailingAnchor constraintEqualToAnchor:container.trailingAnchor],
...@@ -427,35 +429,36 @@ ...@@ -427,35 +429,36 @@
UIView *buttonsContainer = sender.superview; UIView *buttonsContainer = sender.superview;
UIView *questionContainer = buttonsContainer.superview; UIView *questionContainer = buttonsContainer.superview;
NSInteger selected = sender.tag; self.selectedNPS = sender.tag;
for (UIButton *btn in buttonsContainer.subviews) { for (UIButton *btn in buttonsContainer.subviews) {
BOOL isSelected = (btn.tag == selected); if (btn.tag <= self.selectedNPS) {
btn.backgroundColor = [self npsColorForValue:btn.tag selected:isSelected]; btn.backgroundColor = [self npsColorForValue:btn.tag];
[btn setTitleColor:isSelected ? UIColor.whiteColor : UIColor.blackColor btn.layer.borderColor = UIColor.clearColor.CGColor;
forState:UIControlStateNormal]; [btn setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
} else {
btn.backgroundColor = UIColor.clearColor;
btn.layer.borderColor = UIColor.lightGrayColor.CGColor;
[btn setTitleColor:UIColor.blackColor forState:UIControlStateNormal];
}
} }
NSNumber *questionId = @(questionContainer.tag); NSNumber *questionId = @(questionContainer.tag);
self.answers[questionId] = @(selected); self.answers[questionId] = @(self.selectedNPS);
NSLog(@"📊 Saved NPS Q%@ = %@", questionId, self.answers[questionId]); NSLog(@"📊 Saved NPS Q%@ = %@", questionId, self.answers[questionId]);
} }
- (UIColor *)npsColorForValue:(NSInteger)value selected:(BOOL)selected { - (UIColor *)npsColorForValue:(NSInteger)value {
UIColor *base;
if (value <= 1) { if (value <= 1) {
base = [UIColor colorWithRed:0.86 green:0.23 blue:0.23 alpha:1.0]; // red return [UIColor colorWithRed:0.86 green:0.23 blue:0.23 alpha:1.0]; // red
} else if (value <= 6) { } else if (value <= 6) {
base = [UIColor colorWithRed:0.96 green:0.58 blue:0.11 alpha:1.0]; // orange return [UIColor colorWithRed:0.96 green:0.58 blue:0.11 alpha:1.0]; // orange
} else if (value <= 8) { } else if (value <= 8) {
base = [UIColor colorWithRed:0.96 green:0.79 blue:0.11 alpha:1.0]; // yellow return [UIColor colorWithRed:0.96 green:0.79 blue:0.11 alpha:1.0]; // yellow
} else { } else {
base = [UIColor colorWithRed:0.24 green:0.70 blue:0.44 alpha:1.0]; // green return [UIColor colorWithRed:0.24 green:0.70 blue:0.44 alpha:1.0]; // green
} }
return selected ? base : [base colorWithAlphaComponent:0.35];
} }
- (UIView *)buildNumberRating:(NSDictionary *)item { - (UIView *)buildNumberRating:(NSDictionary *)item {
...@@ -464,11 +467,7 @@ ...@@ -464,11 +467,7 @@
container.tag = [item[@"id"] integerValue]; container.tag = [item[@"id"] integerValue];
// Question // Question
UILabel *label = [[UILabel alloc] init]; UILabel *label = [self buildQuestionLabel:item];
label.text = item[@"question"];
label.font = [UIFont systemFontOfSize:14 weight:UIFontWeightBold];
label.numberOfLines = 0;
label.translatesAutoresizingMaskIntoConstraints = NO;
[container addSubview:label]; [container addSubview:label];
// Helper // Helper
...@@ -487,42 +486,36 @@ ...@@ -487,42 +486,36 @@
[container addSubview:buttonsContainer]; [container addSubview:buttonsContainer];
NSInteger count = [item[@"number_of_rates"] integerValue]; NSInteger count = [item[@"number_of_rates"] integerValue];
CGFloat buttonSize = 40;
CGFloat spacing = 8; CGFloat spacing = 8;
CGFloat maxWidth = UIScreen.mainScreen.bounds.size.width - 32 - 32; CGFloat size = [self buttonSizeForCount:MIN(count, 8) spacing:spacing];
CGFloat x = 0; NSMutableArray *buttons = [NSMutableArray array];
CGFloat y = 0;
for (int i = 1; i <= count; i++) { for (int i = 1; i <= count; i++) {
if (x + buttonSize > maxWidth) {
x = 0;
y += buttonSize + spacing;
}
UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem]; UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem];
btn.frame = CGRectMake(x, y, buttonSize, buttonSize);
btn.tag = i; btn.tag = i;
btn.layer.cornerRadius = 6; btn.layer.cornerRadius = 6;
btn.layer.borderWidth = 1; btn.layer.borderWidth = 1;
btn.layer.borderColor = UIColor.lightGrayColor.CGColor; btn.layer.borderColor = UIColor.lightGrayColor.CGColor;
btn.backgroundColor = UIColor.whiteColor;
[btn setTitle:[NSString stringWithFormat:@"%d", i] forState:UIControlStateNormal]; [btn setTitle:[NSString stringWithFormat:@"%d", i]
forState:UIControlStateNormal];
[btn setTitleColor:UIColor.blackColor forState:UIControlStateNormal]; [btn setTitleColor:UIColor.blackColor forState:UIControlStateNormal];
[btn addTarget:self [btn addTarget:self
action:@selector(onNumberTapped:) action:@selector(onNumberTapped:)
forControlEvents:UIControlEventTouchUpInside]; forControlEvents:UIControlEventTouchUpInside];
[buttonsContainer addSubview:btn]; [buttons addObject:btn];
x += buttonSize + spacing;
} }
CGFloat totalHeight = y + buttonSize; CGFloat height = [self layoutButtons:buttons
[buttonsContainer.heightAnchor constraintEqualToConstant:totalHeight].active = YES; inContainer:buttonsContainer
maxPerRow:8
spacing:spacing
buttonSize:size];
[buttonsContainer.heightAnchor constraintEqualToConstant:height].active = YES;
// Constraints // Constraints
[NSLayoutConstraint activateConstraints:@[ [NSLayoutConstraint activateConstraints:@[
...@@ -532,7 +525,7 @@ ...@@ -532,7 +525,7 @@
helper.hidden ? helper.hidden ?
[buttonsContainer.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:8] : [buttonsContainer.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:8] :
[helper.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:6], [helper.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:12],
[helper.leadingAnchor constraintEqualToAnchor:container.leadingAnchor], [helper.leadingAnchor constraintEqualToAnchor:container.leadingAnchor],
[helper.trailingAnchor constraintEqualToAnchor:container.trailingAnchor], [helper.trailingAnchor constraintEqualToAnchor:container.trailingAnchor],
...@@ -568,52 +561,43 @@ ...@@ -568,52 +561,43 @@
NSLog(@"🔢 Saved Q%@ = %@", questionId, self.answers[questionId]); NSLog(@"🔢 Saved Q%@ = %@", questionId, self.answers[questionId]);
} }
- (UIView *)buildQuestionPlaceholder:(NSDictionary *)item {
UIView *container = [[UIView alloc] init];
container.translatesAutoresizingMaskIntoConstraints = NO;
UILabel *label = [[UILabel alloc] init];
label.text = item[@"question"];
label.font = [UIFont systemFontOfSize:14 weight:UIFontWeightBold];
label.translatesAutoresizingMaskIntoConstraints = NO;
[container addSubview:label];
UISegmentedControl *seg = [[UISegmentedControl alloc] initWithItems:@[@"0",@"1",@"2",@"3",@"4",@"5",@"6",@"7",@"8",@"9",@"10"]];
seg.translatesAutoresizingMaskIntoConstraints = NO;
[container addSubview:seg];
[NSLayoutConstraint activateConstraints:@[
[label.topAnchor constraintEqualToAnchor:container.topAnchor],
[label.leadingAnchor constraintEqualToAnchor:container.leadingAnchor],
[label.trailingAnchor constraintEqualToAnchor:container.trailingAnchor],
[seg.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:8],
[seg.leadingAnchor constraintEqualToAnchor:container.leadingAnchor],
[seg.trailingAnchor constraintEqualToAnchor:container.trailingAnchor],
[seg.bottomAnchor constraintEqualToAnchor:container.bottomAnchor],
]];
return container;
}
- (void)onSubmit { - (void)onSubmit {
NSLog(@"submit pressed"); NSLog(@"submit pressed");
// Validate mandatory fields
// for (NSDictionary *section in self.surveyData[@"section"]) { // 1️⃣ Validate mandatory questions
// for (NSDictionary *q in section[@"survey"]) { for (NSDictionary *section in self.surveyData[@"section"]) {
// BOOL mandatory = [q[@"mandatory"] boolValue]; for (NSDictionary *question in section[@"survey"]) {
// NSInteger qId = [q[@"id"] integerValue]; NSInteger qId = [question[@"id"] integerValue];
// if (mandatory && (!self.answers[@(qId)] || BOOL mandatory = [question[@"mandatory"] boolValue];
// [self.answers[@(qId)] isEqual:@""])) {
// NSLog(@"❌ Question %ld is mandatory", (long)qId); if (mandatory) {
// return; id answer = self.answers[@(qId)];
// }
// } // Check empty or nil
// } BOOL emptyAnswer = NO;
// if (!answer) {
// // Call API emptyAnswer = YES;
// [self requestSubmitSurvey]; } else if ([answer isKindOfClass:[NSString class]] && [(NSString *)answer length] == 0) {
emptyAnswer = YES;
}
if (emptyAnswer) {
NSString *msg = [NSString stringWithFormat:@"Please answer mandatory question:\n%@", question[@"question"]];
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Incomplete"
message:msg
preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"OK"
style:UIAlertActionStyleDefault
handler:nil]];
[self presentViewController:alert animated:YES completion:nil];
return; // stop submission
}
}
}
}
// 2️⃣ All mandatory answered, proceed to submit
[self requestSubmitSurvey];
} }
#pragma mark - API #pragma mark - API
...@@ -655,6 +639,7 @@ ...@@ -655,6 +639,7 @@
} }
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
self.surveyData = survey;
self.surveyId = [survey[@"id"] integerValue]; self.surveyId = [survey[@"id"] integerValue];
self.question = survey[@"question"]; self.question = survey[@"question"];
self.type = survey[@"type"]; self.type = survey[@"type"];
...@@ -668,20 +653,88 @@ ...@@ -668,20 +653,88 @@
}]; }];
} }
- (UIView *)buildQuestionPlaceholder:(NSDictionary *)item {
UIView *container = [[UIView alloc] init];
container.translatesAutoresizingMaskIntoConstraints = NO;
UILabel *label = [self buildQuestionLabel:item];
[container addSubview:label];
UISegmentedControl *seg = [[UISegmentedControl alloc] initWithItems:@[@"0",@"1",@"2",@"3",@"4",@"5",@"6",@"7",@"8",@"9",@"10"]];
seg.translatesAutoresizingMaskIntoConstraints = NO;
[container addSubview:seg];
[NSLayoutConstraint activateConstraints:@[
[label.topAnchor constraintEqualToAnchor:container.topAnchor],
[label.leadingAnchor constraintEqualToAnchor:container.leadingAnchor],
[label.trailingAnchor constraintEqualToAnchor:container.trailingAnchor],
[seg.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:8],
[seg.leadingAnchor constraintEqualToAnchor:container.leadingAnchor],
[seg.trailingAnchor constraintEqualToAnchor:container.trailingAnchor],
[seg.bottomAnchor constraintEqualToAnchor:container.bottomAnchor],
]];
return container;
}
- (void)requestSubmitSurvey { - (void)requestSubmitSurvey {
// NSMutableArray *payload = [NSMutableArray array];
// [self.answers enumerateKeysAndObjectsUsingBlock:^(NSNumber *surveyId, id answer, BOOL *stop) { if (self.answers.count == 0) {
// [payload addObject:@{@"surveyId": surveyId, @"value": answer}]; NSLog(@"❌ No answers to submit");
// }]; return;
// }
// [APIClient submitSurvey:payload completion:^(BOOL success, NSError *error) {
// if (success) { NSMutableDictionary<NSNumber *, NSDictionary *> *formattedAnswers =
// NSLog(@"✅ Survey submitted!"); [NSMutableDictionary dictionary];
// [self dismissViewControllerAnimated:YES completion:nil];
// } else { [self.answers enumerateKeysAndObjectsUsingBlock:^(NSNumber *questionId,
// NSLog(@"❌ Failed to submit survey: %@", error); id value,
// } BOOL *stop) {
// }];
NSString *valueString = @"";
NSString *commentString = @"";
if ([value isKindOfClass:[NSString class]]) {
// Comment-only question
commentString = value;
} else {
// Rating / NPS / star
valueString = [value description];
}
formattedAnswers[questionId] = @{
@"value": valueString,
@"comment": commentString
};
}];
NSLog(@"📦 Submitting survey answers: %@", formattedAnswers);
[APIClient requestSubmitSurveyWithFormId:[NSString stringWithFormat:@"%ld",
(long)self.surveyId]
surveyAnswers:formattedAnswers
completion:^(BOOL success,
NSDictionary *response,
NSError *error) {
if (!success || error) {
NSLog(@"❌ Submit failed: %@", error);
return;
}
NSDictionary *appData = response[@"AppData"];
if (![appData[@"status"] isEqualToString:@"success"]) {
NSLog(@"❌ Submit error: %@", appData[@"message"]);
return;
}
NSLog(@"✅ Survey submitted successfully");
dispatch_async(dispatch_get_main_queue(), ^{
[self onBack];
});
}];
} }
- (NSString *)buildRatesHelperText:(NSArray *)labels { - (NSString *)buildRatesHelperText:(NSArray *)labels {
...@@ -703,4 +756,85 @@ ...@@ -703,4 +756,85 @@
return parts.count > 0 ? [parts componentsJoinedByString:@" "] : nil; return parts.count > 0 ? [parts componentsJoinedByString:@" "] : nil;
} }
- (CGFloat)buttonSizeForCount:(NSInteger)count spacing:(CGFloat)spacing {
CGFloat horizontalPadding = 32; // match your container padding
CGFloat availableWidth = UIScreen.mainScreen.bounds.size.width - horizontalPadding;
CGFloat rawSize = (availableWidth - (spacing * (count - 1))) / count;
return MIN(36, floor(rawSize));
}
- (CGFloat)layoutButtons:(NSArray<UIButton *> *)buttons
inContainer:(UIView *)container
maxPerRow:(NSInteger)maxPerRow
spacing:(CGFloat)spacing
buttonSize:(CGFloat)buttonSize {
CGFloat x = 0;
CGFloat y = 0;
NSInteger index = 0;
for (UIButton *btn in buttons) {
if (index > 0 && index % maxPerRow == 0) {
x = 0;
y += buttonSize + spacing;
}
btn.frame = CGRectMake(x, y, buttonSize, buttonSize);
[container addSubview:btn];
x += buttonSize + spacing;
index++;
}
return y + buttonSize;
}
- (UILabel *)buildQuestionLabel:(NSDictionary *)item {
UILabel *label = [[UILabel alloc] init];
label.font = [UIFont systemFontOfSize:15 weight:UIFontWeightBold];
label.numberOfLines = 0;
label.translatesAutoresizingMaskIntoConstraints = NO;
NSString *question = item[@"question"] ?: @"";
BOOL mandatory = [item[@"mandatory"] boolValue];
if (mandatory) {
NSMutableAttributedString *attr =
[[NSMutableAttributedString alloc] initWithString:
[NSString stringWithFormat:@"* %@", question]];
[attr addAttribute:NSForegroundColorAttributeName
value:UIColor.redColor
range:NSMakeRange(0, 1)];
[attr addAttribute:NSForegroundColorAttributeName
value:UIColor.blackColor
range:NSMakeRange(2, attr.length - 2)];
label.attributedText = attr;
} else {
label.text = question;
}
return label;
}
- (void)appendFormField:(NSMutableData *)body
boundary:(NSString *)boundary
key:(NSString *)key
value:(NSString *)value {
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary]
dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:
@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", key]
dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"%@\r\n", value ?: @""]
dataUsingEncoding:NSUTF8StringEncoding]];
}
@end @end
...@@ -108,6 +108,11 @@ NS_ASSUME_NONNULL_BEGIN ...@@ -108,6 +108,11 @@ NS_ASSUME_NONNULL_BEGIN
+ (void)requestSurvey:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion; + (void)requestSurvey:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion;
+ (void)requestSubmitSurveyWithFormId:(NSString *)formId
surveyAnswers:(NSDictionary<NSNumber *, NSDictionary *> *)answers
completion:(void(^)(BOOL success, NSDictionary * _Nullable response, NSError * _Nullable error))completion;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END
...@@ -2623,6 +2623,108 @@ ...@@ -2623,6 +2623,108 @@
[task resume]; [task resume];
} }
+ (void)requestSubmitSurveyWithFormId:(NSString *)formId
surveyAnswers:(NSDictionary<NSNumber *, NSDictionary *> *)answers
completion:(void(^)(BOOL success,
NSDictionary * _Nullable response,
NSError * _Nullable error))completion {
NSURL *url = [APIConfig urlWithPath:@"/framework/owner/survey/submitSurvey"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
// 🧱 Multipart boundary
NSString *boundary = [NSString stringWithFormat:@"Boundary-%@", [[NSUUID UUID] UUIDString]];
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
[request setValue:contentType forHTTPHeaderField:@"Content-Type"];
NSMutableData *body = [NSMutableData data];
// 🔧 Helper to append a form field
void (^appendFormField)(NSString *, NSString *) = ^(NSString *key, NSString *value) {
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary]
dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:
@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", key]
dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"%@\r\n", value ?: @""]
dataUsingEncoding:NSUTF8StringEncoding]];
};
appendFormField(@"data[os]", [APIConfig os]);
appendFormField(@"data[drawing_plan_id]", [APIConfig drawingPlanId]);
appendFormField(@"data[survey][form_id]", formId);
// Device / app info
NSString *infoJson = [APIConfig deviceInfoJson]; // or inline JSON if needed
appendFormField(@"data[information]", infoJson);
[answers enumerateKeysAndObjectsUsingBlock:^(NSNumber *questionId,
NSDictionary *answer,
BOOL *stop) {
NSString *valueKey =
[NSString stringWithFormat:@"data[survey][%@][value]", questionId];
NSString *commentKey =
[NSString stringWithFormat:@"data[survey][%@][comment]", questionId];
NSString *value = @"";
NSString *comment = @"";
if (answer[@"value"] != nil) {
value = [answer[@"value"] description];
}
if (answer[@"comment"] != nil) {
comment = [answer[@"comment"] description];
}
appendFormField(valueKey, value);
appendFormField(commentKey, comment);
}];
// 🔚 Close multipart body
[body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary]
dataUsingEncoding:NSUTF8StringEncoding]];
request.HTTPBody = body;
NSLog(@"🌍 Submit Survey URL: %@", url.absoluteString);
NSLog(@"📦 Submit Survey Body:\n%@",
[[NSString alloc] initWithData:body encoding:NSUTF8StringEncoding]);
NSURLSessionDataTask *task =
[[NSURLSession sharedSession] dataTaskWithRequest:request
completionHandler:^(NSData *data,
NSURLResponse *response,
NSError *error) {
if (error) {
NSLog(@"❌ Submit survey network error: %@", error);
dispatch_async(dispatch_get_main_queue(), ^{
if (completion) completion(NO, nil, error);
});
return;
}
NSError *jsonErr = nil;
NSDictionary *json =
[NSJSONSerialization JSONObjectWithData:data
options:0
error:&jsonErr];
NSLog(@"🧩 Submit Survey response: %@", json);
dispatch_async(dispatch_get_main_queue(), ^{
if (completion) {
completion(jsonErr == nil, json, jsonErr);
}
});
}];
[task resume];
}
#pragma mark - Helper Methods #pragma mark - Helper Methods
+ (NSString *)multipartFormField:(NSString *)name value:(NSString *)value boundary:(NSString *)boundary { + (NSString *)multipartFormField:(NSString *)name value:(NSString *)value boundary:(NSString *)boundary {
......
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