Skip to content

Commit 6f0877c

Browse files
authored
Merge pull request #198 from TaskarCenterAtUW/feature-notes-api-implementation
Submit Notes API implementation
2 parents 0a81489 + e1cbde5 commit 6f0877c

File tree

5 files changed

+148
-30
lines changed

5 files changed

+148
-30
lines changed

GoInfoGame/GoInfoGame.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@
192192
FA5071962D6DD31A00CE9798 /* LongElementQuest.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA5071952D6DD31A00CE9798 /* LongElementQuest.swift */; };
193193
FA5071982D71F1B000CE9798 /* SyncLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA5071972D71F1B000CE9798 /* SyncLogger.swift */; };
194194
FA50719A2D7263F800CE9798 /* LongFormImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA5071992D7263F800CE9798 /* LongFormImageView.swift */; };
195+
FA51484E2D76ED6C00C0D35B /* NotesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA51484D2D76ED6300C0D35B /* NotesViewModel.swift */; };
195196
FA5853C12B21F17F00301CDA /* OnboardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA5853C02B21F17F00301CDA /* OnboardingView.swift */; };
196197
FA87A8102B68142F000A6BEA /* LoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA87A80F2B68142F000A6BEA /* LoadingView.swift */; };
197198
FA87A8132B6AC019000A6BEA /* StepsRampTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA87A8112B6AC019000A6BEA /* StepsRampTests.swift */; };
@@ -503,6 +504,7 @@
503504
FA5071952D6DD31A00CE9798 /* LongElementQuest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LongElementQuest.swift; sourceTree = "<group>"; };
504505
FA5071972D71F1B000CE9798 /* SyncLogger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncLogger.swift; sourceTree = "<group>"; };
505506
FA5071992D7263F800CE9798 /* LongFormImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LongFormImageView.swift; sourceTree = "<group>"; };
507+
FA51484D2D76ED6300C0D35B /* NotesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotesViewModel.swift; sourceTree = "<group>"; };
506508
FA5853C02B21F17F00301CDA /* OnboardingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingView.swift; sourceTree = "<group>"; };
507509
FA87A80F2B68142F000A6BEA /* LoadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingView.swift; sourceTree = "<group>"; };
508510
FA87A8112B6AC019000A6BEA /* StepsRampTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StepsRampTests.swift; sourceTree = "<group>"; };
@@ -797,6 +799,7 @@
797799
971902102B983EFC009B3270 /* CustomMap.swift */,
798800
FA50718B2D54E08800CE9798 /* AddFeatureView.swift */,
799801
FA50718F2D5B31CC00CE9798 /* CreateNoteView.swift */,
802+
FA51484D2D76ED6300C0D35B /* NotesViewModel.swift */,
800803
);
801804
path = Map;
802805
sourceTree = "<group>";
@@ -2108,6 +2111,7 @@
21082111
973FC03F2B59418B00878269 /* WayLit.swift in Sources */,
21092112
971342772BBD415600174EBF /* InitialViewController.swift in Sources */,
21102113
A40004EC2B62338400AF21FB /* AppQuestManager.swift in Sources */,
2114+
FA51484E2D76ED6C00C0D35B /* NotesViewModel.swift in Sources */,
21112115
FAFDA2062C6E8D7A00ECEAE9 /* APIEndPoint.swift in Sources */,
21122116
FA5853C12B21F17F00301CDA /* OnboardingView.swift in Sources */,
21132117
A4B83AF32B5F9385006684CA /* StoredWay.swift in Sources */,

GoInfoGame/GoInfoGame/Network/APIEndPoint.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,5 +110,15 @@ struct APIEndpoint {
110110
return APIEndpoint(path: "/sequence/finished-uploading/", method: "POST", body: nil, headers: nil, formData: formData)
111111

112112
}
113+
114+
static let submitNote = { (note: String, accessToken: String, lat: Double, long: Double, workspaceId: String) in
115+
let header = [
116+
"Authorization": "Bearer \(accessToken)",
117+
"X-Workspace": workspaceId,
118+
"Content-Type": "application/xml"
119+
]
120+
return APIEndpoint(path: "/notes?lat=\(lat)&lon=\(long)&text=\(note)", method: "POST", body: nil, headers: header, formData: nil)
121+
122+
}
113123
}
114124

GoInfoGame/GoInfoGame/UI/Map/CreateNoteView.swift

Lines changed: 77 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,53 +6,101 @@
66
//
77

88
import SwiftUI
9+
import CoreLocation
910

1011
struct CreateNoteView: View {
1112

13+
@State var coordinates: CLLocationCoordinate2D
1214
@State private var noteText = ""
1315
@Binding var showNotesBox: Bool
16+
@State private var alertMessage = ""
17+
@StateObject private var noteViewModel = NotesViewModel()
18+
19+
@State var dismissSheet: (String) -> ()
1420

1521
var body: some View {
16-
VStack(alignment: .leading, spacing: 10) {
17-
TextEditor(text: $noteText)
18-
.padding(10)
19-
.background(Color(.systemGray6))
20-
.cornerRadius(8)
21-
.padding(.horizontal, 20)
22-
23-
HStack {
24-
Button("Submit") {
25-
submitNote()
26-
showNotesBox = false
27-
}
28-
.padding()
29-
.frame(maxWidth: .infinity)
30-
.background(Color.blue)
31-
.foregroundColor(.white)
32-
.cornerRadius(8)
33-
.padding(.horizontal, 20)
22+
ZStack {
23+
VStack(alignment: .leading, spacing: 10) {
24+
TextEditor(text: $noteText)
25+
.padding(10)
26+
.background(Color(.systemGray6))
27+
.cornerRadius(8)
28+
.padding(.horizontal, 20)
3429

35-
Button("Cancel") {
36-
showNotesBox = false
30+
HStack {
31+
Button(action: {
32+
Task {
33+
do {
34+
try await submitNote()
35+
} catch {
36+
print("Error adding feature: \(error)")
37+
}
38+
}
39+
}) {
40+
if noteViewModel.isLoading {
41+
ProgressView()
42+
} else {
43+
Text("Submit")
44+
.font(.custom("Lato-Bold", size: 16))
45+
.foregroundColor(.white)
46+
.padding()
47+
.frame(maxWidth: .infinity)
48+
.background(noteText != "" ? Color(red: 135/255, green: 62/255, blue: 242/255) : Color.gray)
49+
.cornerRadius(9)
50+
}
51+
}
52+
53+
Button (action: {
54+
showNotesBox = false
55+
}) {
56+
Text("Cancel")
57+
.font(.custom("Lato-Bold", size: 16))
58+
.foregroundColor(.white)
59+
.padding()
60+
.frame(maxWidth: .infinity)
61+
.background(Color.red)
62+
.cornerRadius(9)
63+
}
3764
}
38-
.padding()
39-
.frame(maxWidth: .infinity)
40-
.background(Color.red)
41-
.foregroundColor(.white)
42-
.cornerRadius(8)
4365
.padding(.horizontal, 20)
4466
}
45-
.padding(.horizontal, 20)
67+
.padding(.top, 10)
68+
69+
if noteViewModel.isLoading {
70+
Color.black.opacity(0.3)
71+
.edgesIgnoringSafeArea(.all)
72+
ActivityView(activityText: "Submitting Note")
73+
}
4674
}
47-
.padding(.top, 10)
4875
}
4976

50-
func submitNote() {
77+
func submitNote() async throws {
5178
print("Note to be submitted: \(noteText)")
79+
80+
do {
81+
let notesResult = try await noteViewModel.createNote(note: noteText, lat: coordinates.latitude, long: coordinates.longitude)
82+
83+
if notesResult {
84+
print("Notes composed successfully")
85+
alertMessage = "Note submitted successfully"
86+
dismissSheet(alertMessage)
87+
88+
}
89+
} catch {
90+
alertMessage = "Error submitting note. Please try again later."
91+
print("Error creating note: \(error.localizedDescription)")
92+
dismissSheet(alertMessage)
93+
}
94+
95+
await MainActor.run {
96+
noteViewModel.isLoading = false
97+
showNotesBox = false
98+
dismissSheet(alertMessage)
99+
}
52100
}
53101
}
54102

55103

56104
#Preview {
57-
CreateNoteView(showNotesBox: .constant(true))
105+
CreateNoteView(coordinates: CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0), showNotesBox: .constant(true), dismissSheet: {_ in })
58106
}

GoInfoGame/GoInfoGame/UI/Map/MapView.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,16 @@ struct MapView: View {
186186
}
187187
}
188188
.sheet(isPresented: $showCreateNoteSheet, content: {
189-
CreateNoteView(showNotesBox: $showCreateNoteSheet)
189+
CreateNoteView(coordinates: tappedCoordinate ?? CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0), showNotesBox: $showCreateNoteSheet, dismissSheet: { message in
190+
if message.contains("wrong") {
191+
alertIcon = "exclamationmark.triangle.fill"
192+
} else {
193+
alertIcon = "checkmark.circle.fill"
194+
}
195+
alertMessage = message
196+
showAlert = true
197+
198+
})
190199
.presentationDetents([.fraction(0.6)])
191200
.presentationDragIndicator(.visible)
192201

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//
2+
// NotesViewModel.swift
3+
// GoInfoGame
4+
//
5+
// Created by Achyut Kumar M on 04/03/25.
6+
//
7+
8+
import Foundation
9+
10+
11+
class NotesViewModel: ObservableObject {
12+
13+
@Published var isLoading = false
14+
15+
init() {}
16+
17+
func createNote(note: String, lat: Double, long: Double) async throws -> Bool {
18+
19+
await MainActor.run {
20+
self.isLoading = true
21+
}
22+
23+
guard let workspaceId = KeychainManager.load(key: "workspaceID") else {
24+
throw NSError(domain: "NoAccessToken", code: 0, userInfo: [NSLocalizedDescriptionKey: "Workspace Error"])
25+
}
26+
27+
guard let accessToken = KeychainManager.load(key: "accessToken") else {
28+
throw NSError(domain: "NoAccessToken", code: 0, userInfo: [NSLocalizedDescriptionKey: "No Access Token found"])
29+
}
30+
31+
return try await withCheckedThrowingContinuation { [weak self] continuation in
32+
ApiManager.shared.performRequest(to: .submitNote(note, accessToken, lat, long, workspaceId), setupType: .osm, modelType: String.self, useJSON: false) { result in
33+
Task { @MainActor in
34+
self?.isLoading = false
35+
}
36+
37+
switch result {
38+
case .success(_):
39+
continuation.resume(returning: true)
40+
case .failure(let failure):
41+
continuation.resume(throwing: failure)
42+
}
43+
}
44+
}
45+
}
46+
}
47+

0 commit comments

Comments
 (0)