payfrit-food-ios/PayfritFood/Views/AccountTab/RegisterSheet.swift
John Pinkyfloyd 71e7ec34f6 Initial commit: PayfritFood iOS app
- SwiftUI + async/await architecture
- Barcode scanning with AVFoundation
- Product display with score ring, NOVA badge, nutrition
- Alternatives with sort/filter
- Auth (login/register)
- Favorites & history
- Account management
- Dark theme
- Connected to food.payfrit.com API (Open Food Facts proxy)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-03-16 16:58:21 -07:00

140 lines
4.9 KiB
Swift

import SwiftUI
struct RegisterSheet: View {
@EnvironmentObject var appState: AppState
@Environment(\.dismiss) private var dismiss
@State private var name = ""
@State private var email = ""
@State private var password = ""
@State private var zipCode = ""
@State private var isLoading = false
@State private var error: String?
var body: some View {
NavigationStack {
ScrollView {
VStack(spacing: 24) {
// Logo
Image(systemName: "leaf.circle.fill")
.font(.system(size: 60))
.foregroundColor(.green)
.padding(.top, 40)
Text("Create Account")
.font(.title.bold())
Text("Sign up to save favorites, track your scan history, and get personalized recommendations.")
.font(.subheadline)
.foregroundColor(.secondary)
.multilineTextAlignment(.center)
.padding(.horizontal)
// Form
VStack(spacing: 16) {
TextField("Name", text: $name)
.textContentType(.name)
.textFieldStyle(.roundedBorder)
TextField("Email", text: $email)
.keyboardType(.emailAddress)
.textContentType(.emailAddress)
.autocapitalization(.none)
.textFieldStyle(.roundedBorder)
SecureField("Password", text: $password)
.textContentType(.newPassword)
.textFieldStyle(.roundedBorder)
TextField("ZIP Code", text: $zipCode)
.keyboardType(.numberPad)
.textContentType(.postalCode)
.textFieldStyle(.roundedBorder)
Text("We use your ZIP code to find stores near you.")
.font(.caption)
.foregroundColor(.secondary)
}
.padding(.horizontal, 24)
if let error = error {
Text(error)
.font(.caption)
.foregroundColor(.red)
}
// Register Button
Button {
register()
} label: {
if isLoading {
ProgressView()
.tint(.black)
} else {
Text("Create Account")
.font(.headline)
}
}
.foregroundColor(.black)
.frame(maxWidth: .infinity)
.padding()
.background(isValid ? Color.green : Color.gray)
.cornerRadius(12)
.disabled(!isValid || isLoading)
.padding(.horizontal, 24)
// Login Link
HStack {
Text("Already have an account?")
.foregroundColor(.secondary)
Button("Log In") {
dismiss()
appState.showLoginSheet = true
}
.foregroundColor(.green)
}
.font(.subheadline)
Spacer(minLength: 40)
}
}
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button("Cancel") {
dismiss()
}
}
}
}
}
private var isValid: Bool {
!name.isEmpty && !email.isEmpty && email.contains("@") && password.count >= 6 && zipCode.count >= 5
}
private func register() {
isLoading = true
error = nil
Task {
do {
let (profile, token) = try await APIService.shared.register(
email: email,
password: password,
name: name,
zipCode: zipCode
)
await appState.setAuth(userId: profile.id, token: token, profile: profile)
await MainActor.run {
dismiss()
}
} catch {
await MainActor.run {
self.error = error.localizedDescription
isLoading = false
}
}
}
}
}