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

Trouble Pulling the data #184

Open
SIMPSJ17 opened this issue Dec 22, 2024 · 1 comment
Open

Trouble Pulling the data #184

SIMPSJ17 opened this issue Dec 22, 2024 · 1 comment
Assignees

Comments

@SIMPSJ17
Copy link

I am trying to use this function to pull data out of an excel sheet when the user selects the file i get Successfully loaded XLSX file.
Found worksheet paths: ["/xl/worksheets/sheet.xml"]
Found worksheet at path: /xl/worksheets/sheet.xml
Error importing file: The data couldn’t be read because it is missing.

i want to take the data from each row and create a dictionary item similar to what i did here in the parse CSV function any help would be great thank you p.s. this is my first app

import FirebaseAuth
import FirebaseFirestore
import MobileCoreServices // Required for file types
import CoreXLSX // Required for parsing XLSX files

class ImportLogListViewModel: NSObject, ObservableObject {
    @Published var isDocumentPickerPresented = false
    @Published var importLogItems: [ImportLogItem] = []
    
    func parseCSV(fileURL: URL) throws -> [ImportLogItem] {
        var items = [ImportLogItem]()
        let contents = try String(contentsOf: fileURL, encoding: .utf8)
        let rows = contents.components(separatedBy: "\n")
        var isFirstLine = true
        let comments = ""
        
        for row in rows {
            if isFirstLine {
                isFirstLine = false
                continue
            }
            
            let columns = row.split(separator: ",").map { String($0) }
            if columns.count == 7 {
                let dateFormatter = DateFormatter()
                dateFormatter.dateFormat = "dd-MMM-yyyy"
                
                let item = ImportLogItem(
                    id: UUID().uuidString,
                    dof: dateFormatter.date(from: columns[1])?.timeIntervalSince1970 ?? 0,
                    acft: columns[0],
                    duty: columns[2],
                    condition: columns[3],
                    seat: columns[4],
                    hours: Double(columns[5]) ?? 0,
                    createdDate: Date().timeIntervalSince1970,
                    comments: comments
                )
                items.append(item)
            }
        }
        return items.sorted(by: { $0.dof < $1.dof })
    }
    
    func parseXLSX(fileURL: URL) throws {
        // Use guard to unwrap the optional value returned by XLSXFile(filepath:)
        guard let file = XLSXFile(filepath: fileURL.path) else {
            throw NSError(domain: "XLSXParseError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Failed to open XLSX file"])
        }
        
        // Debug: Successfully loaded the XLSX file
        print("Successfully loaded XLSX file.")
        
        // Parse worksheet paths
        guard let sheetPaths = try? file.parseWorksheetPaths() else {
            throw NSError(domain: "XLSXParseError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Failed to parse worksheet paths"])
        }
        
        // Debug: Check the sheet paths found
        print("Found worksheet paths: \(sheetPaths)")
        
        guard let sheetPath = sheetPaths.first else {
            throw NSError(domain: "XLSXParseError", code: -1, userInfo: [NSLocalizedDescriptionKey: "No worksheets found in the file"])
        }
        
        // Debug: Check the worksheet path
        print("Found worksheet at path: \(sheetPath)")
        
        // Parse the worksheet
        let worksheet = try file.parseWorksheet(at: sheetPath)
        
        // Process rows in the worksheet
        let rows = worksheet.data?.rows ?? []
        
        // Debug: Log the number of rows
        print("Found \(rows.count) rows in the worksheet.")
        
        for (rowIndex, row) in rows.enumerated() {
            print("Processing row \(rowIndex + 1):")
            
            // Map columns to values
            let columns = row.cells.map { cell -> String in
                return cell.value ?? ""
            }
            
            // Print the columns for this row
            for (index, column) in columns.enumerated() {
                print("Column \(index + 1): \(column)")
            }
        }
    }


    func pickSpreadsheetFile() {
        let documentPicker = UIDocumentPickerViewController(forOpeningContentTypes: [.commaSeparatedText, .spreadsheet])
        documentPicker.delegate = self
        documentPicker.allowsMultipleSelection = false
        
        if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
           let rootViewController = windowScene.windows.first?.rootViewController {
            rootViewController.present(documentPicker, animated: true, completion: nil)
        }
    }
    
    func saveImportLogItems() {
        guard let uId = Auth.auth().currentUser?.uid else {
            print("User not authenticated.")
            return
        }
        
        let db = Firestore.firestore()
        let logsCollectionRef = db.collection("users").document(uId).collection("FlightLog")
        
        logsCollectionRef.whereField("entryCount", isLessThan: 1500).limit(to: 1).getDocuments { [self] snapshot, error in
            if let error = error {
                print("Error retrieving documents: \(error.localizedDescription)")
                return
            }
            
            if let document = snapshot?.documents.first {
                let documentRef = document.reference
                
                var entryCount = document.data()["entryCount"] as? Int ?? 0
                var currentLogs = document.data()["logs"] as? [[String: Any]] ?? []
                
                for item in self.importLogItems {
                    if entryCount < 1500 {
                        let seatPosition = (item.acft == "AH-64E" || item.acft == "AH-64D") ? item.seat : ""
                        
                        let newLog = [
                            "id": UUID().uuidString,
                            "dof": item.dof,
                            "acft": item.acft,
                            "duty": item.duty,
                            "condition": item.condition,
                            "seat": seatPosition,
                            "hours": item.hours,
                            "createdDate": item.createdDate,
                            "comments": ""
                        ] as [String : Any]
                        
                        currentLogs.append(newLog)
                        entryCount += 1
                    }
                }
                
                documentRef.updateData([
                    "logs": currentLogs,
                    "entryCount": entryCount
                ]) { error in
                    if let error = error {
                        print("Error updating document: \(error.localizedDescription)")
                    } else {
                        print("Logs added to existing document.")
                    }
                }
            }
        }
    }
}

extension ImportLogListViewModel: UIDocumentPickerDelegate {
    func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
        guard let fileURL = urls.first else {
            return
        }

        if fileURL.startAccessingSecurityScopedResource() {
            defer {
                fileURL.stopAccessingSecurityScopedResource()
            }
            
            do {
                if fileURL.pathExtension == "csv" {
                    importLogItems = try parseCSV(fileURL: fileURL)
                } else if fileURL.pathExtension == "xlsx" {
                    try parseXLSX(fileURL: fileURL)
                }
                print("File imported successfully.")
            } catch {
                print("Error importing file: \(error.localizedDescription)")
            }
        } else {
            print("Error: Failed to start accessing security-scoped resource.")
        }
    }
    
    func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
        print("Document picker was cancelled.")
    }
}

@SIMPSJ17
Copy link
Author

SIMPSJ17 commented Feb 8, 2025

func parseXLSX(fileURL: URL) throws {
guard let file = XLSXFile(filepath: fileURL.path) else {
throw NSError(domain: "XLSXParseError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Failed to open XLSX file"])
}

    print("Successfully loaded XLSX file.")

    guard let sharedStrings = try? file.parseSharedStrings() else {
        throw NSError(domain: "XLSXParseError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Failed to parse shared strings"])
    }

    guard let sheetPaths = try? file.parseWorksheetPaths(), let sheetPath = sheetPaths.first else {
        throw NSError(domain: "XLSXParseError", code: -1, userInfo: [NSLocalizedDescriptionKey: "No worksheets found in the file"])
    }

    print("Found worksheet at path: \(sheetPath)")

    let worksheet = try file.parseWorksheet(at: sheetPath)
    let rows = worksheet.data?.rows ?? []

    print("Found \(rows.count) rows in the worksheet.")

    var items = [ImportLogItem]()
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "dd-MMM-yyyy"

    // Set the base date as January 1, 1900 (Excel's epoch)
    let baseDate = Calendar.current.date(from: DateComponents(year: 1900, month: 1, day: 1))!

    for (rowIndex, row) in rows.enumerated() {
        print("Processing row \(rowIndex + 1):")

        var columns: [String] = []

        for cell in row.cells {
            if let stringValue = cell.stringValue(sharedStrings) {
                // Shared String
                columns.append(stringValue)
            } else if let cellValue = cell.value {
                // Inline or raw value
                columns.append("\(cellValue)") // Ensure to convert to string
            } else {
                columns.append("") // Fallback for empty cells
            }
        }

        print("Raw column values: \(columns)")

        if columns.count >= 7 {
            let acftValue = columns[0]
            let dofValue = columns[1]  // The Excel serial date as an integer
            let dutyValue = columns[2]
            let conditionValue = columns[3]
            let seatValue = columns[4]
            let hoursValue = columns[5]
            let commentsValue = columns.count > 6 ? columns[6] : ""

            print("""
                  Mapped Values:
                  acft: \(acftValue)
                  dof: \(dofValue)
                  duty: \(dutyValue)
                  condition: \(conditionValue)
                  seat: \(seatValue)
                  hours: \(hoursValue)
                  comments: \(commentsValue)
                  """)

            // Convert dofValue from string to Int
            if let dofIntValue = Int(dofValue) {
                // Add the Excel serial date value (days since January 1, 1900) to the base date (January 1, 1900)
                let adjustedDate = Calendar.current.date(byAdding: .day, value: dofIntValue - 2, to: baseDate)!

                // Print the adjusted date to check if it matches the expected output
                let adjustedDateString = dateFormatter.string(from: adjustedDate)
                print("Adjusted Date (should be 06 Dec 2022): \(adjustedDateString)")

                let item = ImportLogItem(
                    id: UUID().uuidString,
                    dof: adjustedDate.timeIntervalSince1970,
                    acft: acftValue,
                    duty: dutyValue,
                    condition: conditionValue,
                    seat: seatValue,
                    hours: Double(hoursValue) ?? 0,
                    createdDate: Date().timeIntervalSince1970,
                    comments: commentsValue
                )
                items.append(item)
            } else {
                print("Failed to convert dofValue to Int: \(dofValue)")
            }
        } else {
            print("Row \(rowIndex + 1) doesn't have enough columns to parse.")
        }
    }

    importLogItems = items.sorted { $0.dof < $1.dof }
    print("Successfully parsed \(items.count) rows.")
}

this ended up fixing my issue it was a pain to get swift to deal with the excel serial dates

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants