BeeBusy

BeeBusy

Spa and Salon Booking App for iOS

What

Develop a simple and easy way for Beauty and Spa Services to recoup lost money due to cancellations. MVP focused on a web portal for posting cancelled deals and an iOS app for being notified and buying last minute cancellations. I was responsible for the icon, small landing site, and iOS app.

What I knew

iOS app development and UI/UX

Before BeeBusy I had practice building many miscellaneous apps that never made it into the App Store. These apps gave me a basic understanding of many of Apple's iOS frameworks.

Evolving UI/UX for a educational math app that had over 500,000 downloads.

Front-end web design

Using my in-depth knowledge of css/scss, html, and javascript to visually create anything imaginable.

What I learned

Context aware animations

Using custom presentation controllers, animated transitioning, and view matching animations to create seamless animations between view controllers.

Purchase products through iOS stripe API

Learning the nuances of time sensitive limited quantity transactions; like multiple transaction conflicts, network failures, and purchase intent timeout invalidation.

Dealing with a GraphQL API

Simplifying data requests with a query based API interface helped dramatically with return structures, evolving models and overall clarity.

func getDeals(at loc:CLLocationCoordinate2D, withinRadius radius:Int, page:Page, completion:(( [Deal]?, Error?) -> Void)?) {
    let graphQL = [
        "query" : "{ deals(search: { lat: \(loc.latitude) lng: \(loc.longitude) radius: \(radius) }, page: {limit:\(page.limit), offset:\(page.offset)}) \(Deal.graphQL) }"
    ]
    
    if let url = URL(string: graphURL) {
        manager.request(url, method: .post, parameters: graphQL, encoding: JSONEncoding.default, headers: nil).responseJSON(completionHandler: { res in
            
            if self.canRequest == false { return }
            
            switch res.result {
            case .success:
                if let data = res.result.value as? [String: [String:Any]] {
                    if let json =  data["data"]?["deals"] as? [[String:Any]] {
                        let deals = json.compactMap{ Deal(JSON: $0) }
                        completion?(deals, nil)
                    }
                }
            case .failure(let error):
                guard let err = error as? URLError else { return }
                self.fail(err: err)
                completion?(nil, error)
            }  
        })
    }
}

Protocol oriented design patterns

Using powerful swift protocols to isolate functionality and requirements into flexible and discrete components.

protocol DataCache: class {
    associatedtype DataType: Equatable
    
    var items:[DataType] {get set}
    func add(_ item:DataType)
    
    static var shared:Self {get}
}

extension DataCache {
    func add(_ item:DataType) {
        if !items.contains(item) {
            items.append(item)
        }
    }
}

final class MapItemCache: DataCache {
    
    typealias DataType = MKMapItem
    
    var items:[MKMapItem] = []
    let geoCoder = CLGeocoder()

    //
    //...
    //
}

Outcome

BeeBusy ended up failing due to a number of factors like lack of strong direction, funding, market demand, and initial business trial commitment.


Let's Work Together

And make something beautiful!

Projects

Obsidian

Obsidian

Questrade Client for iOS

Read More