Commit 33030498 authored by Wei Han's avatar Wei Han

survey done

parent 02bbb1d6
......@@ -22,7 +22,8 @@
@property (nonatomic, assign) BOOL mandatory;
@property (nonatomic, strong) NSArray<NSDictionary *> *ratesChecklist;
@property (nonatomic, strong) NSMutableDictionary<NSNumber *, id> *answers;
@property (nonatomic, assign) NSInteger selectedNPS;
@property (nonatomic, strong) NSDictionary *surveyData;
@end
......@@ -32,6 +33,7 @@
self.view.backgroundColor = UIColor.whiteColor;
self.answers = [NSMutableDictionary dictionary];
self.selectedNPS = -1;
[self setupHeader];
[self setupScrollView];
[self requestSurvey];
......@@ -169,7 +171,7 @@
[self.submitButton setTitle:@"Submit" forState:UIControlStateNormal];
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.layer.cornerRadius = 8;
self.submitButton.layer.cornerRadius = 12;
self.submitButton.translatesAutoresizingMaskIntoConstraints = NO;
[self.submitButton addTarget:self action:@selector(onSubmit) forControlEvents:UIControlEventTouchUpInside];
[self.contentView addSubview:self.submitButton];
......@@ -198,10 +200,11 @@
} else if ([type isEqualToString:@"rateNps"]) {
return [self buildNPSRating:item];
} else {
return [self buildQuestionPlaceholder:item];
}
return [self buildQuestionPlaceholder:item];
}
return [self buildQuestionPlaceholder:item];
return [self buildQuestionPlaceholder:item];
}
- (UIView *)buildStarRating:(NSDictionary *)item {
......@@ -210,11 +213,7 @@
container.tag = [item[@"id"] integerValue];
// Question
UILabel *label = [[UILabel alloc] init];
label.text = item[@"question"];
label.font = [UIFont systemFontOfSize:14 weight:UIFontWeightBold];
label.numberOfLines = 0;
label.translatesAutoresizingMaskIntoConstraints = NO;
UILabel *label = [self buildQuestionLabel:item];
[container addSubview:label];
// Helper
......@@ -232,29 +231,40 @@
starsContainer.translatesAutoresizingMaskIntoConstraints = NO;
[container addSubview:starsContainer];
NSInteger rawCount = [item[@"number_of_rates"] integerValue];
NSInteger starCount = MIN(rawCount, 5);
NSInteger count = [item[@"number_of_rates"] integerValue];
count = MAX(1, count);
CGFloat size = 32;
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];
star.frame = CGRectMake((i - 1) * (size + spacing), 0, size, size);
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
action:@selector(onStarTapped:)
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.heightAnchor constraintEqualToConstant:size].active = YES;
[starsContainer.heightAnchor constraintEqualToConstant:height].active = YES;
// Constraints
[NSLayoutConstraint activateConstraints:@[
......@@ -263,8 +273,8 @@
[label.trailingAnchor constraintEqualToAnchor:container.trailingAnchor],
helper.hidden ?
[starsContainer.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:8] :
[helper.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:6],
[starsContainer.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:12] :
[helper.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:12],
[helper.leadingAnchor constraintEqualToAnchor:container.leadingAnchor],
[helper.trailingAnchor constraintEqualToAnchor:container.trailingAnchor],
......@@ -303,10 +313,7 @@
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;
UILabel *label = [self buildQuestionLabel:item];
[container addSubview:label];
UITextField *textField = [[UITextField alloc] init];
......@@ -344,11 +351,7 @@
container.tag = [item[@"id"] integerValue];
// Question
UILabel *label = [[UILabel alloc] init];
label.text = item[@"question"];
label.font = [UIFont systemFontOfSize:14 weight:UIFontWeightBold];
label.numberOfLines = 0;
label.translatesAutoresizingMaskIntoConstraints = NO;
UILabel *label = [self buildQuestionLabel:item];
[container addSubview:label];
// Helper
......@@ -364,42 +367,41 @@
// Buttons container
UIView *buttonsContainer = [[UIView alloc] init];
buttonsContainer.translatesAutoresizingMaskIntoConstraints = NO;
[container addSubview:buttonsContainer];
CGFloat size = 36;
CGFloat spacing = 8;
NSInteger count = [item[@"number_of_rates"] integerValue];
CGFloat spacing = 6;
CGFloat size = [self buttonSizeForCount:MIN(count, 8) spacing:spacing];
NSInteger value = 0;
CGFloat x = 0;
CGFloat y = 0;
NSMutableArray *buttons = [NSMutableArray array];
for (int i = 0; i <= 10; i++) {
// Wrap after 8 → row 2 (9,10)
if (i == 9) {
x = 0;
y += size + spacing;
}
for (int i = 0; i < count; i++) {
UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem];
btn.tag = i;
UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem];
btn.frame = CGRectMake(x, y, size, size);
btn.tag = i;
btn.layer.cornerRadius = 6;
btn.backgroundColor = [self npsColorForValue:i selected:NO];
btn.layer.cornerRadius = 6;
btn.layer.borderWidth = 1;
btn.layer.borderColor = UIColor.lightGrayColor.CGColor;
[btn setTitle:[NSString stringWithFormat:@"%d", i] forState:UIControlStateNormal];
[btn setTitleColor:UIColor.blackColor forState:UIControlStateNormal];
[btn setTitle:[NSString stringWithFormat:@"%d", i]
forState:UIControlStateNormal];
[btn setTitleColor:UIColor.blackColor forState:UIControlStateNormal];
[btn addTarget:self
action:@selector(onNPSTapped:)
forControlEvents:UIControlEventTouchUpInside];
[btn addTarget:self
action:@selector(onNPSTapped:)
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:totalHeight].active = YES;
[buttonsContainer.heightAnchor constraintEqualToConstant:height].active = YES;
// Constraints
[NSLayoutConstraint activateConstraints:@[
......@@ -409,7 +411,7 @@
helper.hidden ?
[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.trailingAnchor constraintEqualToAnchor:container.trailingAnchor],
......@@ -427,35 +429,36 @@
UIView *buttonsContainer = sender.superview;
UIView *questionContainer = buttonsContainer.superview;
NSInteger selected = sender.tag;
self.selectedNPS = sender.tag;
for (UIButton *btn in buttonsContainer.subviews) {
BOOL isSelected = (btn.tag == selected);
btn.backgroundColor = [self npsColorForValue:btn.tag selected:isSelected];
[btn setTitleColor:isSelected ? UIColor.whiteColor : UIColor.blackColor
forState:UIControlStateNormal];
if (btn.tag <= self.selectedNPS) {
btn.backgroundColor = [self npsColorForValue:btn.tag];
btn.layer.borderColor = UIColor.clearColor.CGColor;
[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);
self.answers[questionId] = @(selected);
self.answers[questionId] = @(self.selectedNPS);
NSLog(@"📊 Saved NPS Q%@ = %@", questionId, self.answers[questionId]);
}
- (UIColor *)npsColorForValue:(NSInteger)value selected:(BOOL)selected {
UIColor *base;
- (UIColor *)npsColorForValue:(NSInteger)value {
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) {
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) {
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 {
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 {
......@@ -464,11 +467,7 @@
container.tag = [item[@"id"] integerValue];
// Question
UILabel *label = [[UILabel alloc] init];
label.text = item[@"question"];
label.font = [UIFont systemFontOfSize:14 weight:UIFontWeightBold];
label.numberOfLines = 0;
label.translatesAutoresizingMaskIntoConstraints = NO;
UILabel *label = [self buildQuestionLabel:item];
[container addSubview:label];
// Helper
......@@ -487,42 +486,36 @@
[container addSubview:buttonsContainer];
NSInteger count = [item[@"number_of_rates"] integerValue];
CGFloat buttonSize = 40;
CGFloat spacing = 8;
CGFloat maxWidth = UIScreen.mainScreen.bounds.size.width - 32 - 32;
CGFloat size = [self buttonSizeForCount:MIN(count, 8) spacing:spacing];
CGFloat x = 0;
CGFloat y = 0;
NSMutableArray *buttons = [NSMutableArray array];
for (int i = 1; i <= count; i++) {
if (x + buttonSize > maxWidth) {
x = 0;
y += buttonSize + spacing;
}
UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem];
btn.frame = CGRectMake(x, y, buttonSize, buttonSize);
btn.tag = i;
btn.layer.cornerRadius = 6;
btn.layer.borderWidth = 1;
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 addTarget:self
action:@selector(onNumberTapped:)
forControlEvents:UIControlEventTouchUpInside];
[buttonsContainer addSubview:btn];
x += buttonSize + spacing;
[buttons addObject:btn];
}
CGFloat totalHeight = y + buttonSize;
[buttonsContainer.heightAnchor constraintEqualToConstant:totalHeight].active = YES;
CGFloat height = [self layoutButtons:buttons
inContainer:buttonsContainer
maxPerRow:8
spacing:spacing
buttonSize:size];
[buttonsContainer.heightAnchor constraintEqualToConstant:height].active = YES;
// Constraints
[NSLayoutConstraint activateConstraints:@[
......@@ -532,7 +525,7 @@
helper.hidden ?
[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.trailingAnchor constraintEqualToAnchor:container.trailingAnchor],
......@@ -568,52 +561,43 @@
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 {
NSLog(@"submit pressed");
// Validate mandatory fields
// for (NSDictionary *section in self.surveyData[@"section"]) {
// for (NSDictionary *q in section[@"survey"]) {
// BOOL mandatory = [q[@"mandatory"] boolValue];
// NSInteger qId = [q[@"id"] integerValue];
// if (mandatory && (!self.answers[@(qId)] ||
// [self.answers[@(qId)] isEqual:@""])) {
// NSLog(@"❌ Question %ld is mandatory", (long)qId);
// return;
// }
// }
// }
//
// // Call API
// [self requestSubmitSurvey];
// 1️⃣ Validate mandatory questions
for (NSDictionary *section in self.surveyData[@"section"]) {
for (NSDictionary *question in section[@"survey"]) {
NSInteger qId = [question[@"id"] integerValue];
BOOL mandatory = [question[@"mandatory"] boolValue];
if (mandatory) {
id answer = self.answers[@(qId)];
// Check empty or nil
BOOL emptyAnswer = NO;
if (!answer) {
emptyAnswer = YES;
} 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
......@@ -655,6 +639,7 @@
}
dispatch_async(dispatch_get_main_queue(), ^{
self.surveyData = survey;
self.surveyId = [survey[@"id"] integerValue];
self.question = survey[@"question"];
self.type = survey[@"type"];
......@@ -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 {
// NSMutableArray *payload = [NSMutableArray array];
// [self.answers enumerateKeysAndObjectsUsingBlock:^(NSNumber *surveyId, id answer, BOOL *stop) {
// [payload addObject:@{@"surveyId": surveyId, @"value": answer}];
// }];
//
// [APIClient submitSurvey:payload completion:^(BOOL success, NSError *error) {
// if (success) {
// NSLog(@"✅ Survey submitted!");
// [self dismissViewControllerAnimated:YES completion:nil];
// } else {
// NSLog(@"❌ Failed to submit survey: %@", error);
// }
// }];
if (self.answers.count == 0) {
NSLog(@"❌ No answers to submit");
return;
}
NSMutableDictionary<NSNumber *, NSDictionary *> *formattedAnswers =
[NSMutableDictionary dictionary];
[self.answers enumerateKeysAndObjectsUsingBlock:^(NSNumber *questionId,
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 {
......@@ -703,4 +756,85 @@
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
......@@ -108,6 +108,11 @@ NS_ASSUME_NONNULL_BEGIN
+ (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
NS_ASSUME_NONNULL_END
......@@ -2623,6 +2623,108 @@
[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
+ (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