diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 7fa1be84..00000000 Binary files a/.DS_Store and /dev/null differ diff --git a/.gitignore b/.gitignore index 166face2..122b39e3 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ *.xcworkspace/xcuserdata/ DerivedData/ build/ +.DS_Store + diff --git a/MobileAcebook.xcodeproj/project.pbxproj b/MobileAcebook.xcodeproj/project.pbxproj index 5506db3b..cdc734b1 100644 --- a/MobileAcebook.xcodeproj/project.pbxproj +++ b/MobileAcebook.xcodeproj/project.pbxproj @@ -7,6 +7,9 @@ objects = { /* Begin PBXBuildFile section */ + 0F81A0C52BCE82C200AED673 /* LoginPageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F81A0C42BCE82C200AED673 /* LoginPageView.swift */; }; + 0F81A0C72BCED6FD00AED673 /* SignUpPageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F81A0C62BCED6FD00AED673 /* SignUpPageView.swift */; }; + 3D9855862BCE82EF007D584D /* Post.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D9855852BCE82EF007D584D /* Post.swift */; }; AE5D85B02AC8A221009680C6 /* MobileAcebookApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE5D85AF2AC8A221009680C6 /* MobileAcebookApp.swift */; }; AE5D85B42AC8A224009680C6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AE5D85B32AC8A224009680C6 /* Assets.xcassets */; }; AE5D85B72AC8A224009680C6 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AE5D85B62AC8A224009680C6 /* Preview Assets.xcassets */; }; @@ -19,6 +22,11 @@ AE5D85E32AC9AFD2009680C6 /* MockAuthenticationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE5D85E22AC9AFD2009680C6 /* MockAuthenticationService.swift */; }; AE5D85E62AC9B077009680C6 /* AuthenticationServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE5D85E52AC9B077009680C6 /* AuthenticationServiceProtocol.swift */; }; AE5D85E82AC9B29A009680C6 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE5D85E72AC9B29A009680C6 /* User.swift */; }; + + D6070C072BD005F5003EFBE5 /* UserLogin.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6070C062BD005F5003EFBE5 /* UserLogin.swift */; }; + + C1615B992BCFEF2800A7AB81 /* PostService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1615B982BCFEF2800A7AB81 /* PostService.swift */; }; + /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -39,6 +47,9 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 0F81A0C42BCE82C200AED673 /* LoginPageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginPageView.swift; sourceTree = ""; }; + 0F81A0C62BCED6FD00AED673 /* SignUpPageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpPageView.swift; sourceTree = ""; }; + 3D9855852BCE82EF007D584D /* Post.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Post.swift; sourceTree = ""; }; AE5D85AC2AC8A221009680C6 /* MobileAcebook.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MobileAcebook.app; sourceTree = BUILT_PRODUCTS_DIR; }; AE5D85AF2AC8A221009680C6 /* MobileAcebookApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MobileAcebookApp.swift; sourceTree = ""; }; AE5D85B32AC8A224009680C6 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -54,6 +65,10 @@ AE5D85E22AC9AFD2009680C6 /* MockAuthenticationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAuthenticationService.swift; sourceTree = ""; }; AE5D85E52AC9B077009680C6 /* AuthenticationServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationServiceProtocol.swift; sourceTree = ""; }; AE5D85E72AC9B29A009680C6 /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; }; + + D6070C062BD005F5003EFBE5 /* UserLogin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserLogin.swift; sourceTree = ""; }; + C1615B982BCFEF2800A7AB81 /* PostService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostService.swift; sourceTree = ""; }; + /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -111,6 +126,8 @@ AE5D85B32AC8A224009680C6 /* Assets.xcassets */, AE5D85B52AC8A224009680C6 /* Preview Content */, AE5D85D92AC8A337009680C6 /* WelcomePageView.swift */, + 0F81A0C42BCE82C200AED673 /* LoginPageView.swift */, + 0F81A0C62BCED6FD00AED673 /* SignUpPageView.swift */, ); path = MobileAcebook; sourceTree = ""; @@ -146,6 +163,7 @@ isa = PBXGroup; children = ( AE5D85E02AC9AFA9009680C6 /* AuthenticationService.swift */, + C1615B982BCFEF2800A7AB81 /* PostService.swift */, ); path = Services; sourceTree = ""; @@ -162,6 +180,8 @@ isa = PBXGroup; children = ( AE5D85E72AC9B29A009680C6 /* User.swift */, + 3D9855852BCE82EF007D584D /* Post.swift */, + D6070C062BD005F5003EFBE5 /* UserLogin.swift */, ); path = Models; sourceTree = ""; @@ -306,9 +326,14 @@ files = ( AE5D85E12AC9AFA9009680C6 /* AuthenticationService.swift in Sources */, AE5D85E62AC9B077009680C6 /* AuthenticationServiceProtocol.swift in Sources */, + D6070C072BD005F5003EFBE5 /* UserLogin.swift in Sources */, AE5D85B02AC8A221009680C6 /* MobileAcebookApp.swift in Sources */, + 3D9855862BCE82EF007D584D /* Post.swift in Sources */, AE5D85E82AC9B29A009680C6 /* User.swift in Sources */, + 0F81A0C72BCED6FD00AED673 /* SignUpPageView.swift in Sources */, AE5D85DA2AC8A337009680C6 /* WelcomePageView.swift in Sources */, + C1615B992BCFEF2800A7AB81 /* PostService.swift in Sources */, + 0F81A0C52BCE82C200AED673 /* LoginPageView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/MobileAcebook.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/MobileAcebook.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..0c67376e --- /dev/null +++ b/MobileAcebook.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,5 @@ + + + + + diff --git a/MobileAcebook.xcodeproj/xcshareddata/xcschemes/MobileAcebook.xcscheme b/MobileAcebook.xcodeproj/xcshareddata/xcschemes/MobileAcebook.xcscheme new file mode 100644 index 00000000..f988e3d0 --- /dev/null +++ b/MobileAcebook.xcodeproj/xcshareddata/xcschemes/MobileAcebook.xcscheme @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MobileAcebook/Assets.xcassets/makers-logo.imageset/makers-logo.png b/MobileAcebook/Assets.xcassets/makers-logo.imageset/makers-logo.png deleted file mode 100644 index 8e9844cb..00000000 Binary files a/MobileAcebook/Assets.xcassets/makers-logo.imageset/makers-logo.png and /dev/null differ diff --git a/MobileAcebook/Assets.xcassets/makers-logo.imageset/Contents.json b/MobileAcebook/Assets.xcassets/paw-logo.imageset/Contents.json similarity index 87% rename from MobileAcebook/Assets.xcassets/makers-logo.imageset/Contents.json rename to MobileAcebook/Assets.xcassets/paw-logo.imageset/Contents.json index 216c5e2c..22adbe44 100644 --- a/MobileAcebook/Assets.xcassets/makers-logo.imageset/Contents.json +++ b/MobileAcebook/Assets.xcassets/paw-logo.imageset/Contents.json @@ -1,11 +1,11 @@ { "images" : [ { - "filename" : "makers-logo.png", "idiom" : "universal", "scale" : "1x" }, { + "filename" : "paw (1).png", "idiom" : "universal", "scale" : "2x" }, diff --git a/MobileAcebook/Assets.xcassets/paw-logo.imageset/paw (1).png b/MobileAcebook/Assets.xcassets/paw-logo.imageset/paw (1).png new file mode 100644 index 00000000..d9038482 Binary files /dev/null and b/MobileAcebook/Assets.xcassets/paw-logo.imageset/paw (1).png differ diff --git a/MobileAcebook/LoginPageView.swift b/MobileAcebook/LoginPageView.swift new file mode 100644 index 00000000..32a3ce34 --- /dev/null +++ b/MobileAcebook/LoginPageView.swift @@ -0,0 +1,102 @@ +// +// WelcomePageView.swift +// MobileAcebook +// +// Created by Josué Estévez Fernández on 30/09/2023. +// + +import SwiftUI + +struct LoginPageView: View { + @State private var username = "" + @State private var password = "" + @State var isShowingPassword: Bool = false + + var body: some View { + NavigationView { + + VStack { + Spacer() + Text("Log in") + .font(.largeTitle) + .bold() + Spacer() + VStack { + Text("Username") .frame(maxWidth: 250, alignment: .topLeading) + + TextField("", text: $username) + .frame(width: 250, height: 40) + .overlay( + RoundedRectangle(cornerRadius: 10) + .stroke(Color.gray) + ) + .multilineTextAlignment(.center) + .autocapitalization(. none) + .accessibilityIdentifier("loginUsername") + }.padding() + VStack { + Text("Password") + .frame(maxWidth: 250, alignment: .topLeading) + Group { + if isShowingPassword { + TextField("", text: $password) + .frame(width: 250, height: 40) + .multilineTextAlignment(.center) + .overlay(RoundedRectangle(cornerRadius: 10) + .stroke(Color.gray)) + }else { + SecureField("", text: $password) + .frame(width: 250, height: 40) + .multilineTextAlignment(.center) + .overlay(RoundedRectangle(cornerRadius: 10) + .stroke(Color.gray)) + } + } + .disableAutocorrection(true) + .autocapitalization(.none) + + Button { + isShowingPassword.toggle() + } label: { + if isShowingPassword { + Text("Hide password") + } else { + Text("Show password") + } + }.padding() + } + + + Button("Submit") { + guard !username.isEmpty && !password.isEmpty else { return } + } + .frame(width: 250, height: 40) + .background(Color(red: 0x50/255, green: 0xB7/255, blue: 0xB7/255)) + .foregroundColor(.white) + .cornerRadius(10) + .padding() + + Spacer() + Spacer() + Spacer() + HStack(spacing:3){ + Text("Don't have an account?") + NavigationLink(destination: SignUpPageView()){ + Text("Sign up here") + .fontWeight(.bold) + } + + //add navigation to login + } + .padding() + } + + } + } +} + +struct LoginPageView_Previews: PreviewProvider { + static var previews: some View { + LoginPageView() + } +} diff --git a/MobileAcebook/Models/Post.swift b/MobileAcebook/Models/Post.swift new file mode 100644 index 00000000..ec1a3ad9 --- /dev/null +++ b/MobileAcebook/Models/Post.swift @@ -0,0 +1,15 @@ +// +// Post.swift +// MobileAcebook +// +// Created by Jess Todd on 16/04/2024. +// + +import Foundation + +public struct Post: Encodable { + let message: String + let date: String + let user: String + let profilePicture: String +} diff --git a/MobileAcebook/Models/User.swift b/MobileAcebook/Models/User.swift index ea748dd0..1daa5af5 100644 --- a/MobileAcebook/Models/User.swift +++ b/MobileAcebook/Models/User.swift @@ -5,7 +5,11 @@ // Created by Josué Estévez Fernández on 01/10/2023. // -public struct User { - let username: String + + +public struct User: Encodable { + let imgUrl: String + let email: String let password: String + let username: String } diff --git a/MobileAcebook/Models/UserLogin.swift b/MobileAcebook/Models/UserLogin.swift new file mode 100644 index 00000000..5e8dfbe9 --- /dev/null +++ b/MobileAcebook/Models/UserLogin.swift @@ -0,0 +1,13 @@ +// +// UserLogin.swift +// MobileAcebook +// +// Created by Maria Basia on 17/04/2024. +// + +import Foundation + +struct UserLogin: Encodable { + let email: String + let password: String +} diff --git a/MobileAcebook/Services/AuthenticationService.swift b/MobileAcebook/Services/AuthenticationService.swift index 9f7181c3..295d2eff 100644 --- a/MobileAcebook/Services/AuthenticationService.swift +++ b/MobileAcebook/Services/AuthenticationService.swift @@ -4,10 +4,64 @@ // // Created by Josué Estévez Fernández on 01/10/2023. // +import Foundation + + class AuthenticationService: AuthenticationServiceProtocol { + struct Response: Codable { + let message : String + } + func signUp(user: User) -> Bool { - // Logic to call the backend API for signing up - return true // placeholder + guard let url = URL(string: "http://localhost:3000/users") else {return false} + + var urlRequest = URLRequest(url: url) + urlRequest.httpMethod = "POST" + urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type") + + let body = user + urlRequest.httpBody = try? JSONEncoder().encode(user) + let task = URLSession.shared.dataTask(with : urlRequest) {data, response, error in + guard let data = data else {return} + do { + let response = try JSONSerialization.jsonObject(with: data, options: .allowFragments) + print(response) + print("User created successfully") + } + catch { + print(error) + } + } + task.resume() + return true } + + func login(userLogin: UserLogin) -> Bool { + guard let url = URL(string: "http://localhost:3000/tokens") else {return false} + + var urlRequest = URLRequest(url: url) + urlRequest.httpMethod = "POST" + urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type") + + let body = userLogin + urlRequest.httpBody = try? JSONEncoder().encode(userLogin) + let task = URLSession.shared.dataTask(with : urlRequest) {data, response, error in + guard let data = data else {return} + do { + let response = try JSONSerialization.jsonObject(with: data, options: .allowFragments) + print("Valid user") + print(response) + } + catch { + print(error) + } + } + task.resume() + return true + } + + + } + diff --git a/MobileAcebook/Services/PostService.swift b/MobileAcebook/Services/PostService.swift new file mode 100644 index 00000000..82ff278a --- /dev/null +++ b/MobileAcebook/Services/PostService.swift @@ -0,0 +1,58 @@ +// +// PostService.swift +// MobileAcebook +// +// Created by Bogdan Stăiculescu on 17/04/2024. +// + +import Foundation + +class postService { + + // response returned on succesful /POST request + struct Response: Codable { + // let message : String + let token: String + } + + + func createPost(post: Post, token: String, completion: @escaping ((String) -> Void)) -> Bool { + // defining URL to which we make the POST on the Backend + guard let url = URL(string: "http://localhost:3000/posts") else + {return false} + + // var that contains the URL request and content + var urlRequest = URLRequest(url: url) + // method of the createPost + urlRequest.httpMethod = "POST" + // value of the URL request that's being sent to backend [application/json] + urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type") + // also passing along Bearer and Token to show authorization + urlRequest.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization") + + // defining the body of the HTTP request + let body = post + + urlRequest.httpBody = try? JSONEncoder().encode(body) + + // defining what we do with the response of our request + let task = URLSession.shared.dataTask(with: urlRequest) {data, response, error in + // ensures there is data that returns after making the request ELSE print error + guard let data = data else {return} + // if there is data + do { + let response = try JSONDecoder().decode(Response.self, from: data) + //print(response.token) + DispatchQueue.main.async { + completion(response.token) + } + print("Post Created") + } + catch { + print(error) + } + } + task.resume() + return true + } +} diff --git a/MobileAcebook/SignUpPageView.swift b/MobileAcebook/SignUpPageView.swift new file mode 100644 index 00000000..7087aeda --- /dev/null +++ b/MobileAcebook/SignUpPageView.swift @@ -0,0 +1,143 @@ +// +// SignUpPageView.swift +// MobileAcebook +// +// Created by Venera Zhargakova on 16/04/2024. +// + +import Foundation + +import SwiftUI + +struct SignUpError: Identifiable { + let id = UUID() + let message: String +} + +let authService = AuthenticationService() + + +struct SignUpPageView: View { + @State private var email = "" + @State private var imgUrl = "" + @State private var username = "" + @State private var password = "" + @State var isShowingPassword: Bool = false + @State private var signUpError: String? = nil + @State private var showAlert = false + @State private var isSignUpComplete = false + + + //errors: + @State private var emailError = "" + let authService = AuthenticationService() + var body: some View { + NavigationView { + VStack(spacing: 30) { + Spacer() + Spacer() + Text("Sign Up") + .font(.largeTitle) + .fontWeight(/*@START_MENU_TOKEN@*/.bold/*@END_MENU_TOKEN@*/) + VStack(spacing:0) { + Text("Email Address") + .frame(maxWidth: 250, alignment: .topLeading) + .padding() + TextField("", text: $email) + .frame(width: 250, height: 40) + .multilineTextAlignment(.center) + .overlay( + RoundedRectangle(cornerRadius: 10) + .stroke(Color.gray) + ) + .autocapitalization(. none) + .accessibilityIdentifier("email") + Text("Full Name") + .frame(maxWidth: 250, alignment: .topLeading) + .padding() + TextField("", text: $username) + .frame(width: 250, height: 40) + .multilineTextAlignment(.center) + .overlay( + RoundedRectangle(cornerRadius: 10) + .stroke(Color.gray) + ) + .autocapitalization(. none) + .accessibilityIdentifier("Full Name") + Text("Password") + .frame(maxWidth: 250, alignment: .topLeading) + .padding() + VStack { + Group { + if isShowingPassword { + TextField("", text: $password) + .frame(width: 250, height: 40) + .multilineTextAlignment(.center) + .overlay(RoundedRectangle(cornerRadius: 10) + .stroke(Color.gray)) + }else { + SecureField("", text: $password) + .frame(width: 250, height: 40) + .multilineTextAlignment(.center) + .overlay(RoundedRectangle(cornerRadius: 10) + .stroke(Color.gray)) + } + } + .disableAutocorrection(true) + .autocapitalization(.none) + + Button { + isShowingPassword.toggle() + } label: { + if isShowingPassword { + Text("Hide password") + } else { + Text("Show password") + } + }.padding() + } + + VStack{ + Button("Sign Up"){ + + let newUser = User(imgUrl: imgUrl, email: email, password: password, username: username) + let success = authService.signUp(user: newUser) + if success { + // Clear fields if signup successful + email = "" + username = "" + password = "" + isSignUpComplete = true + + + // Show success message + signUpError = "Account created successfully" + } else { + // Show error message + signUpError = "Error creating account" + } + + } + .frame(width: 250, height: 40) + .background(Color(red: 0x50/255, green: 0xB7/255, blue: 0xB7/255)) + .foregroundColor(.white) + .cornerRadius(10) + } + } + .padding(.top, 40) + Spacer() + HStack(spacing:3){ + Text("Already have an account?") + NavigationLink(destination: LoginPageView(), isActive: $isSignUpComplete, label: {Text("Login here") + .fontWeight(.bold)}) + } + } + + } + } + } + #Preview { + SignUpPageView() + } + + diff --git a/MobileAcebook/WelcomePageView.swift b/MobileAcebook/WelcomePageView.swift index 96006af9..03d8a325 100644 --- a/MobileAcebook/WelcomePageView.swift +++ b/MobileAcebook/WelcomePageView.swift @@ -9,34 +9,75 @@ import SwiftUI struct WelcomePageView: View { var body: some View { - ZStack { - VStack { - Spacer() - - Text("Welcome to Acebook!") - .font(.largeTitle) - .padding(.bottom, 20) - .accessibilityIdentifier("welcomeText") - - Spacer() - - Image("makers-logo") - .resizable() - .scaledToFit() - .frame(width: 200, height: 200) - .accessibilityIdentifier("makers-logo") - - Spacer() - - Button("Sign Up") { - // TODO: sign up logic +<<<<<<< HEAD + NavigationView{ +======= + NavigationView { +>>>>>>> bddf4de293ba456171c3682d257fba2a9996240b + ZStack { + VStack { + Spacer() + + Text("Welcome to\n Pawbook!") + .font(.largeTitle) + .padding(.bottom, 25) + .accessibilityIdentifier("welcomeText") + .multilineTextAlignment(.center) + .foregroundColor(Color(red: 0.50, green: 0.71, blue: 0.71)) + .bold() + Spacer() + + Image("paw-logo") + .resizable() + .scaledToFit() + .frame(width: 130, height: 130) + .accessibilityIdentifier("paw-logo") + Spacer() + +<<<<<<< HEAD + NavigationLink(destination: LoginPageView()) { + Button("Login") { + // TODO: login logic + } + .frame(width: 250, height: 40) + .background(Color(red: 0x50/255, green: 0xB7/255, blue: 0xB7/255)) + .foregroundColor(.white) + .cornerRadius(10) + .accessibilityIdentifier("loginButton")} + + NavigationLink(destination: SignUpPageView()) { + Button(action: { + }) { + Text("Sign Up") + .frame(width: 250, height: 40) + .background(Color(red: 0x50/255, green: 0xB7/255, blue: 0xB7/255)) + .foregroundColor(.white) + .cornerRadius(10) + .accessibilityIdentifier("signUpButton") + } +======= + NavigationLink(destination: LoginPageView()){ + Text("Login") + .frame(width: 250, height: 40) + .background(Color(red: 0x50/255, green: 0xB7/255, blue: 0xB7/255)) + .foregroundColor(.white) + .cornerRadius(10) + .accessibilityIdentifier("loginButton") + } + NavigationLink(destination: SignUpPageView()){ + Text("Sign Up") + .frame(width: 250, height: 40) + .background(Color(red: 0x50/255, green: 0xB7/255, blue: 0xB7/255)) + .foregroundColor(.white) + .cornerRadius(10) + .accessibilityIdentifier("signUpButton") +>>>>>>> bddf4de293ba456171c3682d257fba2a9996240b + } + + Spacer() } - .accessibilityIdentifier("signUpButton") - - Spacer() } - } - } + }} } struct WelcomePageView_Previews: PreviewProvider {