Skip to content
Merged
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
127 changes: 127 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
name: Build with Firebase CLI
on:
push:
branches:
- 'main'

jobs:
build:
name: Build iOS app IPA
runs-on: macos-latest
steps:
# Step 1: Checkout the code
- name: Checkout
uses: actions/checkout@v4

# Step 2: Set up the Build environment
- name: Setup Build Environment
run: |
# Set BUILD_ENV based on branch name
echo "BUILD_ENV=DEV" >> $GITHUB_ENV
echo "FIREBASE_APP_ID_SECRET_NAME=FIREBASE_APP_ID_DEV" >> $GITHUB_ENV
echo "PROVISIONING_PROFILE_NAME=PROVISIONING_PROFILE" >> $GITHUB_ENV
echo "PROVISIONING_PROFILE_SPECIFIER_NAME=<PROFILE_NAME>" >> $GITHUB_ENV
echo "SCHEME_NAME=<SCHEME_NAME>" >> $GITHUB_ENV
echo "PRODUCT_NAME=PETRO-PASS\ DEV" >> $GITHUB_ENV
echo "PLIST_FILE_NAME=GoogleService-Info-dev.plist" >> $GITHUB_ENV

- name: Verify BUILD_ENV
run: |
echo "Current BUILD_ENV: ${{ env.BUILD_ENV }}"
echo "Firebase App Id: ${{ secrets[env.FIREBASE_APP_ID_SECRET_NAME] }}"
echo "Provisioning Profile: ${{ secrets[env.PROVISIONING_PROFILE_NAME] }}"
echo "Provisioning Profile Specifier: ${{ env.PROVISIONING_PROFILE_SPECIFIER_NAME}}"
echo "Scheme Name: ${{ env.SCHEME_NAME }}"
echo "Product Name: ${{ env.PRODUCT_NAME }}"
echo "Plist File Name: ${{ env.PLIST_FILE_NAME }}"

#Step 3: Set up the environment (CocoaPods, etc)
- name: Set up Ruby for CocoaPods
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.1.0'

- name: Get xcodebuild version
run: |
sudo xcode-select -s "/Applications/Xcode_16.1.app"
xcodebuild -version

- name: Install CocoaPods Dependencies
run: |
gem install cocoapods
pod install

#Step 4: Set up Provisioning Profile and Certificates
- name: Set up Provisioning Profile and Certificates
env:
CERT_DATA: ${{ secrets.P12_CERTIFICATE }}
CERT_PW: ${{ secrets.P12_PASSWORD }}
run: |

mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
echo "${{ secrets[env.PROVISIONING_PROFILE_NAME] }}" | base64 --decode > ~/Library/MobileDevice/Provisioning\ Profiles/profile.mobileprovision

# Create and unlock keychain
security create-keychain -p "" build.keychain
security list-keychains -s build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p "" build.keychain
security set-keychain-settings

echo $CERT_DATA | base64 --decode > signingCertificate.p12
echo "certificate decoded"
security import signingCertificate.p12 -f pkcs12 -k build.keychain -P $CERT_PW -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple: -s -k "" build.keychain

file signingCertificate.p12

rm signingCertificate.p12

#Step 5: Clean and Build the iOS App
- name: Clean and Build the iOS App
run: |
xcodebuild clean \
-workspace <WORKSPACE_NAME>.xcworkspace \
-scheme "${{ env.SCHEME_NAME }}" \
-configuration "AdHoc" \
-sdk iphoneos \
-quiet

echo "Clean success"

# Archive the app
xcodebuild -scheme "${{ env.SCHEME_NAME }}" -workspace <WORKSPACE_NAME>.xcworkspace -sdk iphoneos -archivePath <WORKSPACE_NAME>.xcarchive clean archive PROVISIONING_PROFILE_SPECIFIER="${{ env.PROVISIONING_PROFILE_SPECIFIER_NAME}}" CODE_SIGN_STYLE="Manual"

echo "Archive success"

- name: Upload dSYM
run: |
ls Pods/FirebaseCrashlytics/
ls Pods/FirebaseCrashlytics
Pods/FirebaseCrashlytics/upload-symbols -gsp <WORKSPACE_NAME>/Firebase/${{ env.PLIST_FILE_NAME }} -p ios <WORKSPACE_NAME>.xcarchive/dSYMs/${{ env.PRODUCT_NAME }}.app.dSYM

- name: Export the IPA
run: |
xcodebuild -exportArchive \
-archivePath <WORKSPACE_NAME>.xcarchive \
-exportOptionsPlist plist/ExportOptions.plist \
-exportPath build

ls build

- name: Install Firebase Tools
run: |
curl -sL https://firebase.tools | bash

- name: Get Firebase Tools Version
run: |
firebase --version

## For dev should be update to APK
- name: Publish App to Firebase App Distribution
run: |
firebase appdistribution:distribute build/${{ env.PRODUCT_NAME }}.ipa \
--app ${{ secrets[env.FIREBASE_APP_ID_SECRET_NAME] }} \
--groups "${{ env.BUILD_ENV }}" \
--release-notes "${{ github.event.head_commit.message }}" \
--token ${{ secrets.FIREBASE_TOKEN }}
6 changes: 4 additions & 2 deletions TorqueNet.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -541,10 +541,11 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = TorqueNet/TorqueNet.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"TorqueNet/Preview Content\"";
DEVELOPMENT_TEAM = JJ5G6DQS7M;
DEVELOPMENT_TEAM = 89SKCJ295N;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = TorqueNet/Info.plist;
Expand Down Expand Up @@ -574,10 +575,11 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = TorqueNet/TorqueNet.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"TorqueNet/Preview Content\"";
DEVELOPMENT_TEAM = JJ5G6DQS7M;
DEVELOPMENT_TEAM = 89SKCJ295N;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = TorqueNet/Info.plist;
Expand Down
Binary file not shown.
59 changes: 56 additions & 3 deletions TorqueNet/Core/Firebase/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,66 @@

import SwiftUI
import FirebaseCore
import FirebaseMessaging
import UserNotifications
import FirebaseAppCheck
import FirebaseCrashlytics


class AppDelegate: NSObject, UIApplicationDelegate {

class AppDelegate: NSObject, UIApplicationDelegate, MessagingDelegate, UNUserNotificationCenterDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
FirebaseApp.configure()

registerFirebase(application: application)
return true
}

private func registerFirebase(application: UIApplication){
application.registerForRemoteNotifications()

let providerFactory = AppCheckDebugProviderFactory() // Use App Check with the debug provider on Apple platforms
AppCheck.setAppCheckProviderFactory(providerFactory)

FirebaseApp.configure()
Messaging.messaging().delegate = self
UNUserNotificationCenter.current().delegate = self
Crashlytics.crashlytics().setCrashlyticsCollectionEnabled(true)
}

//Firebase
// set APNs token
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Messaging.messaging().apnsToken = deviceToken
print("DEBUG: APNs token is \(deviceToken)")
}

func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("DEBUG: Failed to register for remote notifications: \(error.localizedDescription)")
}

//Recieve FCM Token
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
print("DEBUG: Getting token")
Constants.FCM_TOKEN = fcmToken ?? ""
print("FCM Token: \(fcmToken ?? "")")

if let fcm = Messaging.messaging().fcmToken {
print("DEBUG: fcm token: ", fcm)
}
}

// handle notifications. This will enable to also to receive notifications in foreground.
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification) async -> UNNotificationPresentationOptions {
// play sound, show badge/banner, and list(notifications that appears when app is locked)
return [.sound, .badge, .banner, .list]
}

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse) async {
print("DEBUG: User tapped the notification.")

// "link" is a key in push notification payload
if let deepLink = response.notification.request.content.userInfo["link"] as? String, let url = URL(string: deepLink) {
print("DEBUG: Received deep link \(deepLink)")
}
}
}
1 change: 1 addition & 0 deletions TorqueNet/Core/Utils/Constant.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

class Constants {
static let isDashboardBottomNavigationVisible = "isDashboardBottomNavigationVisible"
static var FCM_TOKEN: String = ""
}


Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ struct AuctionUploadModel: Identifiable, Codable {
let startingBid: Double
let currentBid: Double
let auctionEndDate: Timestamp
let startDate: Timestamp
let endDate: Timestamp
let auctionStatus: String
let createdAt: Timestamp
let updatedAt: Timestamp
Expand Down Expand Up @@ -66,6 +68,8 @@ struct AuctionUploadModel: Identifiable, Codable {
case startingBid = "starting_bid"
case currentBid = "current_bid"
case auctionEndDate = "auction_end_date"
case startDate = "start_date"
case endDate = "end_date"
case auctionStatus = "auction_status"
case createdAt = "created_at"
case updatedAt = "updated_at"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ class UploadAuctionUseCase {
rating: Double,
startingBid: String,
auctionEndDate: Date,
startDate: Date,
endDate: Date,
auctionStatus: UploadAuctionStatus,
mileage: String,
year: String,
Expand Down Expand Up @@ -109,6 +111,8 @@ class UploadAuctionUseCase {
startingBid: bidAmount,
currentBid: bidAmount,
auctionEndDate: Timestamp(date: auctionEndDate),
startDate: Timestamp(date: startDate),
endDate: Timestamp(date: endDate),
auctionStatus: auctionStatus.rawValue,
createdAt: Timestamp(date: Date()),
updatedAt: Timestamp(date: Date()),
Expand Down Expand Up @@ -161,6 +165,8 @@ class UploadAuctionUseCase {
startingBid: auction.startingBid,
currentBid: auction.currentBid,
auctionEndDate: Timestamp(date: newEndTime ?? Date()),
startDate: auction.startDate,
endDate: auction.endDate,
auctionStatus: newStatus,
createdAt: auction.createdAt,
updatedAt: Timestamp(date: Date()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -944,14 +944,14 @@ struct BidSheetView: View {
}
.disabled(auctionDetailsUiState.bidAmount.isEmpty)
}
.background(Color.theme.surfaceColor)
.padding()
.navigationBarTitleDisplayMode(.inline)
.navigationBarItems(
trailing: Button("Cancel") {
presentationMode.wrappedValue.dismiss()
}
)
.background(Color.theme.surfaceColor)

}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,10 @@ struct AuctionFormState {
var transmissionDetails: String = ""
var electronicsRating: Double = 9.0
var electronicsDetails: String = ""

//Schedule auction
var startDate: Date = Date().addingTimeInterval(3600)
var endDate: Date = Date().addingTimeInterval(86400)
var scheduleError: String = ""
}

Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,17 @@ struct AuctionUploadView: View {
}
}
.pickerStyle(.segmented)

AuctionScheduleComponent(
startDate: $uploadAuctionViewModel.form.startDate,
endDate: $uploadAuctionViewModel.form.endDate,
startingBid: $uploadAuctionViewModel.form.startingBid,
scheduleError: $uploadAuctionViewModel.form.scheduleError,
onValidate: {
uploadAuctionViewModel.validateSchedule()
}
)
.transition(.opacity.combined(with: .scale))
}
.padding()
.background(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ class AuctionUploadViewModel: ObservableObject {
rating: form.rating,
startingBid: form.startingBid,
auctionEndDate: form.auctionEndDate,
startDate: form.startDate,
endDate: form.endDate,
auctionStatus: form.auctionStatus,
mileage: form.mileage,
year: form.year,
Expand Down Expand Up @@ -268,6 +270,37 @@ class AuctionUploadViewModel: ObservableObject {
ui = AuctionUploadUIState()
form = AuctionFormState()
}

func validateSchedule() {
form.scheduleError = ""

if form.startDate <= Date() {
form.scheduleError = "Start date must be in the future"
return
}

let oneHourFromNow = Date().addingTimeInterval(3600)
if form.startDate < oneHourFromNow {
form.scheduleError = "Start date must be at least 1 hour from now"
return
}

if form.endDate <= form.startDate {
form.scheduleError = "End date must be after start date"
return
}

if !form.startingBid.isEmpty {
if let bid = Double(form.startingBid), bid <= 0 {
form.scheduleError = "Starting bid must be greater than 0"
return
} else if Double(form.startingBid) == nil {
form.scheduleError = "Please enter a valid starting bid"
return
}
}
}



func saveDraft() {
Expand Down
Loading