Skip to content

Finished project: Achieved MVP #134

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

Open
wants to merge 13 commits into
base: master
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
405 changes: 405 additions & 0 deletions GigsApp/GigsApp.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
64 changes: 64 additions & 0 deletions GigsApp/GigsApp/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
<key>UISceneDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
<key>UISceneStoryboardFile</key>
<string>Main</string>
</dict>
</array>
</dict>
</dict>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
206 changes: 206 additions & 0 deletions GigsApp/GigsApp/Model Controller/GigController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
//
// GigController.swift
// GigsApp
//
// Created by Clayton Watkins on 5/8/20.
// Copyright © 2020 Clayton Watkins. All rights reserved.
//

import Foundation

class GigController {

//MARK: - Properties
enum HTTPMethod: String {
case get = "GET"
case post = "POST"
}

enum NetworkError: Error{
case noData
case noToken
case failedSignUp
case failedSignIn
case tryAgain
case failedToPost
}

var gigList: [Gigs] = []
var bearer: Bearer?
private let baseURL = URL(string: "https://lambdagigapi.herokuapp.com/api")!
private lazy var signUpUrl = baseURL.appendingPathComponent("/users/signup")
private lazy var signInUrl = baseURL.appendingPathComponent("/users/login")
private lazy var accessGigsURL = baseURL.appendingPathComponent("/gigs")

//MARK: - Functions
//Function to sign up
func signUp(with user: User, completion: @escaping (Result<Bool, NetworkError>) -> Void) {
print("signUpURL = \(signUpUrl.absoluteString)")

var request = postRequest(for: signUpUrl)

do{
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let jsonData = try encoder.encode(user)
print(String(data: jsonData, encoding: .utf8)!)
request.httpBody = jsonData

let task = URLSession.shared.dataTask(with: request) { (_, response, error) in
if let error = error {
print("Sign up failed with error: \(error)")
completion(.failure(.failedSignUp))
return
}

guard let response = response as? HTTPURLResponse,
response.statusCode == 200 else {
print("Sign up was unsucessful")
completion(.failure(.failedSignUp))
return
}
completion(.success(true))
}
task.resume()
} catch {
print("Error encoding user: \(error)")
completion(.failure(.failedSignUp))
}
}

//Function to sign in
func signIn(with user: User, completion: @escaping (Result<Bool, NetworkError>) -> Void){
var request = postRequest(for: signInUrl)

do{
let encoder = JSONEncoder()
let jsonData = try encoder.encode(user)
request.httpBody = jsonData

URLSession.shared.dataTask(with: request) { (data, response, error) in
if let error = error{
print("Sign in failed with error: \(error)")
completion(.failure(.failedSignIn))
return
}

guard let response = response as? HTTPURLResponse,
response.statusCode == 200 else {
print("Sign in was unsucessful")
completion(.failure(.failedSignIn))
return
}

guard let data = data else{
print("Data was not recived")
completion(.failure(.failedSignIn))
return
}

do{
let decoder = JSONDecoder()
self.bearer = try decoder.decode(Bearer.self, from: data)
completion(.success(true))
} catch {
print("Error decoding bearer: \(error)")
completion(.failure(.noToken))
return
}
}.resume()
} catch {
print("Error encoding user: \(error)")
completion(.failure(.failedSignIn))
}
}

func getAllGigs(completion: @escaping (Result<[Gigs], NetworkError>) -> Void){
guard let bearer = bearer.self else {
completion(.failure(.noToken))
return
}

var request = URLRequest(url: accessGigsURL)
request.httpMethod = HTTPMethod.get.rawValue
request.setValue("Bearer \(bearer.token)", forHTTPHeaderField: "Authorization")

let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
if let error = error{
completion(.failure(.tryAgain))
print("Error reciving data: \(error)")
return
}

if let response = response as? HTTPURLResponse,
response.statusCode == 401 {
completion(.failure(.noToken))
}

guard let data = data else{
print("No data recieved")
completion(.failure(.noData))
return
}

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
do{
let gigs = try decoder.decode([Gigs].self, from: data)
self.gigList = gigs
completion(.success(gigs))
} catch {
print("Error decoding gigs from data: \(error)")
completion(.failure(.tryAgain))
}
}
task.resume()
}

func createGig(title: String, dueDate: Date, description: String, completion: @escaping (Result<Gigs, NetworkError>) -> Void){
guard let bearer = bearer.self else{
completion(.failure(.noToken))
return
}

let newGig = Gigs(title: title, description: description, dueDate: dueDate)

var request = URLRequest(url: accessGigsURL)
request.httpMethod = HTTPMethod.post.rawValue
request.setValue("Bearer \(bearer.token)", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")

let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601
do{
request.httpBody = try encoder.encode(newGig)
self.gigList.append(newGig)
} catch{
print("Error encoding new gig: \(error)")
completion(.failure(.failedToPost))
return
}

let task = URLSession.shared.dataTask(with: request) { (_, response, error) in
if let error = error{
print("Error sending created gig: \(error)")
completion(.failure(.failedToPost))
return
}

if let response = response as? HTTPURLResponse,
response.statusCode == 401{
completion(.failure(.tryAgain))
return
}
completion(.success(newGig))
}
task.resume()
}

//MARK: - Helper Functions
private func postRequest(for url: URL) -> URLRequest {
var request = URLRequest(url: url)
request.httpMethod = HTTPMethod.post.rawValue
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
return request
}
}
13 changes: 13 additions & 0 deletions GigsApp/GigsApp/Models/Bearer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// Bearer.swift
// GigsApp
//
// Created by Clayton Watkins on 5/8/20.
// Copyright © 2020 Clayton Watkins. All rights reserved.
//

import Foundation

struct Bearer: Codable{
let token: String
}
15 changes: 15 additions & 0 deletions GigsApp/GigsApp/Models/Gig.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// Gig.swift
// GigsApp
//
// Created by Clayton Watkins on 5/12/20.
// Copyright © 2020 Clayton Watkins. All rights reserved.
//

import Foundation

struct Gigs: Codable{
var title: String
var description: String
var dueDate: Date
}
14 changes: 14 additions & 0 deletions GigsApp/GigsApp/Models/User.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// User.swift
// GigsApp
//
// Created by Clayton Watkins on 5/8/20.
// Copyright © 2020 Clayton Watkins. All rights reserved.
//

import Foundation

struct User: Codable {
var username: String
var password: String
}
37 changes: 37 additions & 0 deletions GigsApp/GigsApp/Resources/AppDelegate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//
// AppDelegate.swift
// GigsApp
//
// Created by Clayton Watkins on 5/8/20.
// Copyright © 2020 Clayton Watkins. All rights reserved.
//

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {



func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}

// MARK: UISceneSession Lifecycle

func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}

func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}


}

Loading