Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get post b #46

Open
wants to merge 26 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified .DS_Store
Binary file not shown.
20 changes: 20 additions & 0 deletions MobileAcebook.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
4FA628172BCED56D00EF9696 /* LogInView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FA628162BCED56D00EF9696 /* LogInView.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 */; };
Expand All @@ -19,6 +20,10 @@
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 */; };
F46B58B32BCE9B8C00430CBB /* SignupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F46B58B22BCE9B8C00430CBB /* SignupView.swift */; };
F48BBE712BD004750090C82B /* Post.swift in Sources */ = {isa = PBXBuildFile; fileRef = F48BBE702BD004750090C82B /* Post.swift */; };
F48BBE752BD005350090C82B /* PostService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F48BBE742BD005350090C82B /* PostService.swift */; };
F48BBE772BD005BF0090C82B /* FeedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F48BBE762BD005BF0090C82B /* FeedView.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand All @@ -39,6 +44,7 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
4FA628162BCED56D00EF9696 /* LogInView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogInView.swift; sourceTree = "<group>"; };
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 = "<group>"; };
AE5D85B32AC8A224009680C6 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
Expand All @@ -54,6 +60,10 @@
AE5D85E22AC9AFD2009680C6 /* MockAuthenticationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAuthenticationService.swift; sourceTree = "<group>"; };
AE5D85E52AC9B077009680C6 /* AuthenticationServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationServiceProtocol.swift; sourceTree = "<group>"; };
AE5D85E72AC9B29A009680C6 /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = "<group>"; };
F46B58B22BCE9B8C00430CBB /* SignupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignupView.swift; sourceTree = "<group>"; };
F48BBE702BD004750090C82B /* Post.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Post.swift; sourceTree = "<group>"; };
F48BBE742BD005350090C82B /* PostService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostService.swift; sourceTree = "<group>"; };
F48BBE762BD005BF0090C82B /* FeedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedView.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -111,6 +121,9 @@
AE5D85B32AC8A224009680C6 /* Assets.xcassets */,
AE5D85B52AC8A224009680C6 /* Preview Content */,
AE5D85D92AC8A337009680C6 /* WelcomePageView.swift */,
F46B58B22BCE9B8C00430CBB /* SignupView.swift */,
4FA628162BCED56D00EF9696 /* LogInView.swift */,
F48BBE762BD005BF0090C82B /* FeedView.swift */,
);
path = MobileAcebook;
sourceTree = "<group>";
Expand Down Expand Up @@ -146,6 +159,7 @@
isa = PBXGroup;
children = (
AE5D85E02AC9AFA9009680C6 /* AuthenticationService.swift */,
F48BBE742BD005350090C82B /* PostService.swift */,
);
path = Services;
sourceTree = "<group>";
Expand All @@ -162,6 +176,7 @@
isa = PBXGroup;
children = (
AE5D85E72AC9B29A009680C6 /* User.swift */,
F48BBE702BD004750090C82B /* Post.swift */,
);
path = Models;
sourceTree = "<group>";
Expand Down Expand Up @@ -304,7 +319,12 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F48BBE772BD005BF0090C82B /* FeedView.swift in Sources */,
F46B58B32BCE9B8C00430CBB /* SignupView.swift in Sources */,
4FA628172BCED56D00EF9696 /* LogInView.swift in Sources */,
AE5D85E12AC9AFA9009680C6 /* AuthenticationService.swift in Sources */,
F48BBE712BD004750090C82B /* Post.swift in Sources */,
F48BBE752BD005350090C82B /* PostService.swift in Sources */,
AE5D85E62AC9B077009680C6 /* AuthenticationServiceProtocol.swift in Sources */,
AE5D85B02AC8A221009680C6 /* MobileAcebookApp.swift in Sources */,
AE5D85E82AC9B29A009680C6 /* User.swift in Sources */,
Expand Down
49 changes: 49 additions & 0 deletions MobileAcebook/FeedView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import SwiftUI

struct FeedView: View {
@ObservedObject private var postService = PostService()
@ObservedObject private var authService = AuthenticationService()

var body: some View {
NavigationView {
VStack {
// Input field and share button
TextField("What's happening?", text: $postService.newPostText)
.font(.body)
.padding(30)
.foregroundColor(Color.red)
.background(Color.yellow)
.cornerRadius(80)

Button(action: {
// This is removed because we only want to fetch and display posts
}) {
Text("Share")
}
List(postService.posts) { post in
VStack(alignment: .leading, spacing: 8) {
// Display the username in a smaller font above the message
Text("Posted by \(post.createdBy.username) at \(post.createdAt)")
.font(.subheadline)
.foregroundColor(.gray)
// Display the post message
Text(post.message)
}
}
.onAppear {
authService.getToken() { token in
if let token = token {
postService.fetchPosts(token: token)
} else {
print("Token is nil")
}
}
}

// Other views as needed
}
.navigationBarTitle("Feed")
}
}
}

77 changes: 77 additions & 0 deletions MobileAcebook/LogInView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import SwiftUI

struct LoginView: View {
@State private var email = ""
@State private var password = ""
@State private var isLoggingIn = false
@State private var loginSuccess = false
@State private var loginMessage = ""

// Inject AuthenticationService instance
@ObservedObject var authService = AuthenticationService()

var body: some View {
VStack {
Spacer()

Text("Welcome back to Fakebook!")
.font(.largeTitle)
.padding(.bottom, 20)
.multilineTextAlignment(.center)
.accessibilityIdentifier("welcomeBackText")

Spacer()

TextField("Email", text: $email)
.padding()
.textFieldStyle(RoundedBorderTextFieldStyle())
SecureField("Password", text: $password)
.padding()
.textFieldStyle(RoundedBorderTextFieldStyle())

if loginSuccess {
Text(loginMessage)
.foregroundColor(.green)
} else {
Text(loginMessage)
.foregroundColor(.red)
}

Button(action: login) {
Text("Log In")
.padding()
.foregroundColor(.white)
.background(Color.green)
.cornerRadius(10)
}
.padding()

Spacer()
.frame(height: 200)
}
.padding()
.alert(isPresented: $isLoggingIn) {
Alert(title: Text("Log In"), message: Text("Logging in..."), dismissButton: .default(Text("OK")))
}
}

func login() {
self.isLoggingIn = true
authService.login(email: email, password: password) { success, message, token in
DispatchQueue.main.async {
self.isLoggingIn = false
if success {
self.loginSuccess = true
self.loginMessage = "Login Successful!"

// Navigate to FeedView upon successful login
let feedView = FeedView() // Assuming FeedView is a SwiftUI view
UIApplication.shared.windows.first?.rootViewController = UIHostingController(rootView: feedView)
} else {
self.loginSuccess = false
self.loginMessage = message ?? "Failed to login"
}
}
}
}
}
57 changes: 57 additions & 0 deletions MobileAcebook/Models/Post.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//
// Post.swift
// MobileAcebook
//
// Created by Benjamin Pearl on 17/04/2024.
//

import Foundation



//public struct Post {
// let id: String
// let message: String
// let author: User
// let timestamp: Date
// var comments: [Comment]
// var likes: [Like]
// var imgUrl: String?
//}
struct PostUser: Decodable {
let _id: String
let profilePicture: String
let username: String
}

struct PostResponse: Decodable{
let posts: [Post]
let token: String
}

struct Post: Identifiable, Equatable, Decodable {
let id: String // Assuming 'id' is a string in your backend schema
let message: String
let createdAt: String // Assuming 'createdAt' is a Date in your backend schema
let createdBy: PostUser // Assuming 'createdBy' is a string representing user ID
var imgUrl: String? // Assuming 'imgUrl' is a String in your backend schema
var likes: [String] // Assuming 'likes' is an array of user IDs as strings

// Implement Equatable protocol
static func == (lhs: Post, rhs: Post) -> Bool {
return lhs.id == rhs.id
}

private enum CodingKeys: String, CodingKey {
case id = "_id"
case message, createdAt, createdBy, imgUrl, likes
}
}








17 changes: 14 additions & 3 deletions MobileAcebook/Models/User.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,18 @@
// Created by Josué Estévez Fernández on 01/10/2023.
//

public struct User {
let username: String
let password: String
import Foundation

public struct User: Codable {
public let username: String
public let password: String
public let email: String
public let imgUrl: String

public init(username: String, password: String, email: String, imgUrl: String) {
self.username = username
self.password = password
self.email = email
self.imgUrl = imgUrl
}
}
3 changes: 2 additions & 1 deletion MobileAcebook/Protocols/AuthenticationServiceProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
//
// Created by Josué Estévez Fernández on 01/10/2023.
//
import Foundation

public protocol AuthenticationServiceProtocol {
func signUp(user: User) -> Bool
func signUp(user: User, completion: @escaping (Bool, String?) -> Void)
}
86 changes: 76 additions & 10 deletions MobileAcebook/Services/AuthenticationService.swift
Original file line number Diff line number Diff line change
@@ -1,13 +1,79 @@
//
// AuthenticationService.swift
// MobileAcebook
//
// Created by Josué Estévez Fernández on 01/10/2023.
//
import Foundation

class AuthenticationService: AuthenticationServiceProtocol {
func signUp(user: User) -> Bool {
// Logic to call the backend API for signing up
return true // placeholder
class AuthenticationService: ObservableObject, AuthenticationServiceProtocol {
private let tokenKey = "authToken" // Key for storing token in UserDefaults

func getToken(completion: @escaping (String?) -> Void) {
if let token = UserDefaults.standard.string(forKey: tokenKey) {
completion(token)
} else {
completion(nil)
}
}

func login(email: String, password: String, completion: @escaping (Bool, String?, String?) -> Void) {
let url = URL(string: "http://localhost:3000/tokens")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")

let loginDetails = ["email": email, "password": password]

do {
request.httpBody = try JSONSerialization.data(withJSONObject: loginDetails, options: [])
} catch {
completion(false, "Failed to encode login data", nil)
return
}

let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
completion(false, "Request error: \(error.localizedDescription)", nil)
return
}

guard let httpResponse = response as? HTTPURLResponse else {
completion(false, "Invalid response", nil)
return
}

guard (200...299).contains(httpResponse.statusCode) else {
completion(false, "HTTP error: \(httpResponse.statusCode)", nil)
return
}

guard let data = data else {
completion(false, "No data received", nil)
return
}

do {
guard let tokenDict = try JSONSerialization.jsonObject(with: data, options: []) as? [String: String] else {
completion(false, "Invalid token data", nil)
return
}

guard let token = tokenDict["token"] else {
completion(false, "Token not found in response", nil)
return
}

// Store token in UserDefaults
UserDefaults.standard.set(token, forKey: self.tokenKey)
UserDefaults.standard.synchronize()

completion(true, nil, token) // Pass token back through completion handler
} catch {
completion(false, "Error decoding response: \(error.localizedDescription)", nil)
}
}
task.resume()
}

// Implementing AuthenticationServiceProtocol method
func signUp(user: User, completion: @escaping (Bool, String?) -> Void) {
// Your implementation for signing up a user
// This method is required by the AuthenticationServiceProtocol
}

}
Loading