Skip to content

Commit

Permalink
add new login screen and remove deeplink login
Browse files Browse the repository at this point in the history
  • Loading branch information
gorkemsevim committed Jun 30, 2024
1 parent c18b20d commit ba33b90
Show file tree
Hide file tree
Showing 17 changed files with 356 additions and 77 deletions.
48 changes: 36 additions & 12 deletions HappyPathTimeTracker.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,12 @@
5E1D44102A59B69400B6BEA4 /* Project.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E1D440F2A59B69400B6BEA4 /* Project.swift */; };
5E1D44122A59B97000B6BEA4 /* ProjectTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E1D44112A59B97000B6BEA4 /* ProjectTask.swift */; };
5E1D44172A5A8A5D00B6BEA4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E1D44162A5A8A5D00B6BEA4 /* AppDelegate.swift */; };
5E397EA82C301A2B00878992 /* LargeButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E397EA72C301A2B00878992 /* LargeButton.swift */; };
5E397EAA2C301EDC00878992 /* RoundedTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E397EA92C301EDC00878992 /* RoundedTextField.swift */; };
5E397EAE2C3024E500878992 /* RecoverSuccessView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E397EAD2C3024E500878992 /* RecoverSuccessView.swift */; };
5E397EB12C30253B00878992 /* RoundedContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E397EB02C30253B00878992 /* RoundedContainer.swift */; };
5E397EB62C30430000878992 /* LoginScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E397EB52C30430000878992 /* LoginScreenViewModel.swift */; };
5E3DAF202A5AF3C4005BB83A /* KeychainSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 5E3DAF1F2A5AF3C4005BB83A /* KeychainSwift */; };
5E3DAF222A5B1F5F005BB83A /* NotificationName.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E3DAF212A5B1F5F005BB83A /* NotificationName.swift */; };
5E3DAF252A5B3718005BB83A /* K.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E3DAF242A5B3718005BB83A /* K.swift */; };
5E41B1442A497F51001E90AC /* HappyPathTimeTrackerApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E41B1432A497F51001E90AC /* HappyPathTimeTrackerApp.swift */; };
5E41B1462A497F51001E90AC /* MainScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E41B1452A497F51001E90AC /* MainScreen.swift */; };
Expand Down Expand Up @@ -141,8 +145,12 @@
5E1D440F2A59B69400B6BEA4 /* Project.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Project.swift; sourceTree = "<group>"; };
5E1D44112A59B97000B6BEA4 /* ProjectTask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProjectTask.swift; sourceTree = "<group>"; };
5E1D44162A5A8A5D00B6BEA4 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
5E397EA72C301A2B00878992 /* LargeButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LargeButton.swift; sourceTree = "<group>"; };
5E397EA92C301EDC00878992 /* RoundedTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundedTextField.swift; sourceTree = "<group>"; };
5E397EAD2C3024E500878992 /* RecoverSuccessView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecoverSuccessView.swift; sourceTree = "<group>"; };
5E397EB02C30253B00878992 /* RoundedContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundedContainer.swift; sourceTree = "<group>"; };
5E397EB52C30430000878992 /* LoginScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginScreenViewModel.swift; sourceTree = "<group>"; };
5E3DAF1A2A5AAC71005BB83A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
5E3DAF212A5B1F5F005BB83A /* NotificationName.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationName.swift; sourceTree = "<group>"; };
5E3DAF242A5B3718005BB83A /* K.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = K.swift; sourceTree = "<group>"; };
5E41B1402A497F51001E90AC /* HappyPathTimeTracker.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HappyPathTimeTracker.app; sourceTree = BUILT_PRODUCTS_DIR; };
5E41B1432A497F51001E90AC /* HappyPathTimeTrackerApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HappyPathTimeTrackerApp.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -258,7 +266,6 @@
isa = PBXGroup;
children = (
5E1D44092A59AF7C00B6BEA4 /* Date.swift */,
5E3DAF212A5B1F5F005BB83A /* NotificationName.swift */,
5E7B54942A611D560097EC94 /* String.swift */,
5E7B54962A6120EE0097EC94 /* Int.swift */,
5EB384602A70F5B200FDA0E0 /* Color.swift */,
Expand All @@ -269,6 +276,22 @@
path = Extension;
sourceTree = "<group>";
};
5E397EAF2C3024ED00878992 /* Views */ = {
isa = PBXGroup;
children = (
5E397EAD2C3024E500878992 /* RecoverSuccessView.swift */,
);
path = Views;
sourceTree = "<group>";
};
5E397EB42C3042EE00878992 /* ViewModels */ = {
isa = PBXGroup;
children = (
5E397EB52C30430000878992 /* LoginScreenViewModel.swift */,
);
path = ViewModels;
sourceTree = "<group>";
};
5E3DAF232A5B370F005BB83A /* Util */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -357,19 +380,13 @@
5E588B142AB1A1AE00F6DB85 /* Login */ = {
isa = PBXGroup;
children = (
5E588B152AB1A1EF00F6DB85 /* Views */,
5E397EB42C3042EE00878992 /* ViewModels */,
5E397EAF2C3024ED00878992 /* Views */,
5E588B162AB1A20A00F6DB85 /* LoginScreen.swift */,
);
path = Login;
sourceTree = "<group>";
};
5E588B152AB1A1EF00F6DB85 /* Views */ = {
isa = PBXGroup;
children = (
);
path = Views;
sourceTree = "<group>";
};
5E797CE02A4B1ED0003FCD06 /* Model */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -405,6 +422,9 @@
5EE372042A4FFCD900859278 /* TimeEntryView.swift */,
5E69F5E42ADC5527000FD1FB /* SearchBar.swift */,
5EF0195E2B779F02004ED61B /* Loading.swift */,
5E397EA72C301A2B00878992 /* LargeButton.swift */,
5E397EA92C301EDC00878992 /* RoundedTextField.swift */,
5E397EB02C30253B00878992 /* RoundedContainer.swift */,
);
path = Components;
sourceTree = "<group>";
Expand Down Expand Up @@ -685,12 +705,13 @@
5E06CAA82A8254680019E411 /* Bundle.swift in Sources */,
5EF0195F2B779F02004ED61B /* Loading.swift in Sources */,
5EE372092A5030D800859278 /* BottomView.swift in Sources */,
5E3DAF222A5B1F5F005BB83A /* NotificationName.swift in Sources */,
5E797CE22A4B1EE4003FCD06 /* CircleDay.swift in Sources */,
5EE372212A50BE7400859278 /* NetworkInterceptorProvider.swift in Sources */,
5E41B1462A497F51001E90AC /* MainScreen.swift in Sources */,
5EE372052A4FFCD900859278 /* TimeEntryView.swift in Sources */,
5E397EB12C30253B00878992 /* RoundedContainer.swift in Sources */,
5E7B54952A611D560097EC94 /* String.swift in Sources */,
5E397EAE2C3024E500878992 /* RecoverSuccessView.swift in Sources */,
5EE372262A50C1A500859278 /* MainScreenViewModel.swift in Sources */,
5EE888DF2B73A68300671E52 /* StartNewTimerView.swift in Sources */,
5E1D44102A59B69400B6BEA4 /* Project.swift in Sources */,
Expand All @@ -706,6 +727,7 @@
5E8FAEF12A6910850016EE08 /* Auth.swift in Sources */,
5E1D44122A59B97000B6BEA4 /* ProjectTask.swift in Sources */,
5E96C8B82A9C931300121C1A /* CalendarView.swift in Sources */,
5E397EAA2C301EDC00878992 /* RoundedTextField.swift in Sources */,
5EB384612A70F5B200FDA0E0 /* Color.swift in Sources */,
5EC4AEA02B7A4F530084D4E9 /* StartNewTimerViewModel.swift in Sources */,
5E69F5E52ADC5527000FD1FB /* SearchBar.swift in Sources */,
Expand All @@ -716,7 +738,9 @@
5EE3721F2A50BD0C00859278 /* GraphqlClient.swift in Sources */,
5E588B172AB1A20A00F6DB85 /* LoginScreen.swift in Sources */,
5EE3720F2A50322E00859278 /* CircleDayView.swift in Sources */,
5E397EB62C30430000878992 /* LoginScreenViewModel.swift in Sources */,
5E96C8B62A9C925800121C1A /* CalendarWeekListView.swift in Sources */,
5E397EA82C301A2B00878992 /* LargeButton.swift in Sources */,
5E1D44172A5A8A5D00B6BEA4 /* AppDelegate.swift in Sources */,
5E7B54972A6120EE0097EC94 /* Int.swift in Sources */,
5EE372032A4FFBA400859278 /* TimeEntry.swift in Sources */,
Expand Down
24 changes: 0 additions & 24 deletions HappyPathTimeTracker/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,8 @@ import SwiftDate
import AppKit

class AppDelegate: NSObject, NSApplicationDelegate {
// will run with deeplink
func application(_ application: NSApplication, open urls: [URL]) {
let components = URLComponents(url: urls[0], resolvingAgainstBaseURL: false)
let token = components?.queryItems?.first(where: {$0.name == "token"})?.value
HappyLogger.logger.log("token: \(token?.debugDescription ?? "no-token")")
if let tokenData = token?.data(using: .utf8) {
if let encodedToken = Data(base64Encoded: tokenData) {
if let encodedToken = try? JSONDecoder().decode(Auth.self, from: encodedToken),
let tokenString = encodedToken.token{
DispatchQueue.global().async {
let store = KeyStore()
store.store(key: K.token, value: tokenString)
}
HappyLogger.logger.log("sharing token")
NotificationCenter.default.post(name: Notification.Name.loginByMagicLinkNotification, object: tokenString)
}
}
} else {
HappyLogger.logger.critical("There is any token in deeplink url")
fatalError()
}
}

func applicationDidFinishLaunching(_ notification: Notification) {
// set default region
SwiftDate.defaultRegion = .local
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"images" : [
{
"filename" : "hummingbird.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 37 additions & 0 deletions HappyPathTimeTracker/Components/LargeButton.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//
// LargeButton.swift
// HappyPathTimeTracker
//
// Created by Gorkem Sevim on 29.06.2024.
//

import Foundation
import SwiftUI

struct LargeButton: View {
let title: String
let color: Color = Color.ShadesOfTeal.Teal_300
let disabled: Bool
let isLoading: Bool
let onClick: () -> Void

var body: some View {
Button(action: onClick, label: {
Text(title)
.foregroundStyle(Color.Primary.RealWhite)
.padding()
.frame(maxWidth: .infinity)
.background {
RoundedRectangle(cornerRadius: 20)
.foregroundStyle(disabled ? Color.ShadesofCadetGray.CadetGray200 : color)
}
.disabled(disabled || isLoading)
})
}
}

#Preview {
LargeButton(title: "Signin", disabled: false, isLoading: true) {
print("signin clicked")
}
}
30 changes: 30 additions & 0 deletions HappyPathTimeTracker/Components/RoundedContainer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// RoundedContainer.swift
// HappyPathTimeTracker
//
// Created by Gorkem Sevim on 29.06.2024.
//

import Foundation
import SwiftUI

struct RoundedContainer<Content: View>: View {
let content: () -> Content

init(@ViewBuilder content: @escaping () -> Content) {
self.content = content
}
var body: some View {
GeometryReader { proxy in
content()
.padding(24)
.background {
Color.Primary.RealWhite
}
.frame(width: proxy.size.width * 0.8)
.clipShape(RoundedRectangle(cornerRadius: 16))
.shadow(radius: 10)
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
}
52 changes: 52 additions & 0 deletions HappyPathTimeTracker/Components/RoundedTextField.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//
// RoundedTextField.swift
// HappyPathTimeTracker
//
// Created by Gorkem Sevim on 29.06.2024.
//

import Foundation
import SwiftUI

struct RoundedTextField: View {
@Binding var text: String
var type: TextFieldType = .text
@State private var isSecure: Bool = true

var body: some View {
HStack {
if type == .text || !isSecure {
TextField("", text: $text)
.textFieldStyle(.plain)
.foregroundColor(.Primary.DarkNight)
.padding(5)
} else {
SecureField("", text: $text)
.textFieldStyle(.plain)
.foregroundColor(.Primary.DarkNight)
.padding(5)
}

if type == .password {
Button(action: {
isSecure.toggle()
}) {
Image(systemName: isSecure ? "eye.slash" : "eye")
.resizable()
.frame(width: 16, height: 12)
.foregroundColor(Color.ShadesOfTeal.Teal_300)
}
.padding(5)
}
}
.overlay(
RoundedRectangle(cornerRadius: 4)
.stroke(Color.ShadesofCadetGray.CadetGray200)
)
}
}

enum TextFieldType {
case text
case password
}
12 changes: 0 additions & 12 deletions HappyPathTimeTracker/Extension/NotificationName.swift

This file was deleted.

5 changes: 0 additions & 5 deletions HappyPathTimeTracker/HappyPathTimeTrackerApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@ struct HappyPathTimeTrackerApp: App {
MenuBarExtra {
MainScreen()
.environmentObject(appState)
.onReceive(NotificationCenter.default.publisher(for: Notification.Name.loginByMagicLinkNotification)) { token in
HappyLogger.logger.log("new token received")
self.appState.isLoggedIn = true
appState.updateClientAuthToken(token: token.object as! String)
}
.environment(\.font, .figtree())
.frame(width: 400, height: 450)
} label: {
Expand Down
19 changes: 19 additions & 0 deletions HappyPathTimeTracker/Managers/NetworkManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import DirectusGraphql
import SwiftDate

protocol NetworkSource {
static func login(email: String, password: String) async -> String?
func me(graphqlClient: GraphqlClient?) async throws -> MeQuery.Data.Me?
func fetchStats(graphqlClient: GraphqlClient?, date: Date) async throws -> Stats?
func fetchProjects(graphqlClient: GraphqlClient?) async throws -> [Project]?
Expand All @@ -25,6 +26,24 @@ protocol NetworkSource {
}

final class NetworkManager: NetworkSource {

static func login(email: String, password: String) async -> String? {
let url = URL(string: "https://app.usehappypath.com/hooks/auth")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let json: [String: String] = ["email": email, "password": password]
let jsonData = try? JSONSerialization.data(withJSONObject: json)
request.httpBody = jsonData

do {
let (data, response) = try await URLSession.shared.data(for: request)
let authResponse = try JSONDecoder().decode(AuthResponse.self, from: data)
return authResponse.token
} catch {
return nil
}
}

func me(graphqlClient: GraphqlClient?) async throws -> MeQuery.Data.Me? {
if graphqlClient == nil {
Expand Down
4 changes: 4 additions & 0 deletions HappyPathTimeTracker/Model/Auth.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,7 @@ struct Metadata: Decodable {
let issuer, publicAddress, email, oauthProvider, phoneNumber: String?
let wallets: [String]?
}

struct AuthResponse: Decodable {
let token: String
}
Loading

0 comments on commit ba33b90

Please sign in to comment.