profile
viewpoint
Ash Furrow ashfurrow @artsy New York https://ashfurrow.com/ Building software with my whole heart.

ashfurrow/AFTabledCollectionView 556

How to display a UICollectionView within a UITableViewCell

artsy/Swift-at-Artsy 290

Repo for the notes for Swift at Artsy

ashfurrow/AFImageDownloader 88

Downloads JPEG images asynchronously and decompresses them on a background thread.

ashfurrow/Angular 33

Making an Othello/Reversi clone

ashfurrow/AFActivityIndicatorView 25

A ground-up, home-made implementation of UIActivityIndicatorView

ashfurrow/500px-API-Test 20

500px recently opened their API to the public. I want to try it out.

ashfurrow/ARAnalytics 5

Simplify your iOS analytics

ashfurrow/ARTiledImageView 5

Display, pan and deep zoom with tiled images on iOS.

artsy/imessage-sticker-experiment 4

Experimental repo for an iMessages stickers app

push eventRxSwiftCommunity/rxswiftcommunity.github.io

Ash Furrow (Via Travis)

commit sha dce2c2f0ff1364564026946974d125fb6d09fd67

Site updated to 153754b

view details

push time in 10 hours

delete branch artsy/metaphysics

delete branch : all-sale-artworks

delete time in 13 hours

PR opened artsy/metaphysics

[MX-378] Adds all argument to sale's saleArtworksConnections field

This PR adds an all argument to the sale's saleArtworksConnection field, to return all sale artworks in a sale in one Metaphysics request. I know this isn't the best practice, but it's use has precedent in v2 (in the fairs resolver) so its use here is justified. The alternative is a significant refactor in Eigen, and possibly Prediction, which I want to avoid.

Screen Shot 2020-07-09 at 4 27 54 PM

I also migrated the unit tests for this file to async/await and to TypeScript. Both these changes are in their own commits, and are best reviewed independently.

+125 -59

0 comment

4 changed files

pr created time in 13 hours

push eventartsy/metaphysics

Ash Furrow

commit sha 63873b81db14f73c2488f033ac426b7c175f8a32

Converts test to TypeScript. Converts test to TypeScript.

view details

push time in 13 hours

create barnchartsy/metaphysics

branch : all-sale-artworks

created branch time in 13 hours

delete branch ashfurrow/metaphysics

delete branch : causlity-jwt-v2

delete time in 19 hours

push eventRxSwiftCommunity/rxswiftcommunity.github.io

Ash Furrow (Via Travis)

commit sha 001974c974c6ca6c3fa6049fad68aca86addc93b

Site updated to 153754b

view details

push time in a day

PR opened artsy/metaphysics

Reviewers
[MX-378] Exposes causalityJWT resolver under system root field

In the process of moving Eigen's few remaining uses of Metaphysics v1 schema to v2, I noticed that the causalityJWT resolver (causality_jwt in v1) had not yet been ported over. This PR exposes the resolver and takes the suggestion left by Eloy to move the resolver from the top-level of the schema into the system resolver.

So, in v1 you would do this:

{
  causality_jwt(role: PARTICIPANT, saleID: "mobile-sprintly-qa")
}

But now in v2, you would do this:

{
  system {
    causalityJWT(role: PARTICIPANT, saleID: "mobile-sprintly-qa")
  }
}

I've tested this locally and it works. I'm tagging in @bhoggard in case this effects the Auctions team's adoption of v2.

+58 -17

0 comment

5 changed files

pr created time in a day

create barnchashfurrow/metaphysics

branch : causlity-jwt-v2

created branch time in a day

issue commentartsy/README

[RFC] Move palette iOS component implementations to the eigen repo

I'm not going to lie, my initial reaction was less-than-enthusiastic. But you've laid out a really convincing argument, and have convinced me. That list of failed Palette update PRs to Eigen, oof. The tradeoffs aren't really worth it anymore; as Chris said, our implementation has gotten us quite far but it might be time to go another route. So I'm a 👍 here.

ds300

comment created time in 2 days

issue commentorta/cocoapods-keys

Is it possible to use this for WatchOS

I'm not sure, I've never built a WatchOS app. If anyone else knows, please sound off 🗣️

auro-krishna

comment created time in 2 days

push eventartsy/eigen

brainbicycle

commit sha 3ca2855ba271685c079c113fecf35e367c5f4833

Update changelog for next version

view details

brainbicycle

commit sha 955fe5ffecb2a8664c84f163423f3f997b800d4c

Update version number

view details

Brian Beckerle

commit sha 14e789099c37cb036136e4fe8f73f0db7d0be50f

Merge branch 'master' into 6.5.0-update

view details

Brian Beckerle

commit sha 1f801a5b221998e6313e9f6a79b7bce4f13d9952

Merge branch 'master' into 6.5.0-update

view details

Ash Furrow

commit sha 739a0098430afbf241be252c3ee44a329f13c138

Merge pull request #3542 from artsy/6.5.0-update Preparing for development version 6.5.0 #trivial

view details

push time in 2 days

delete branch artsy/eigen

delete branch : 6.5.0-update

delete time in 2 days

PR merged artsy/eigen

Preparing for development version 6.5.0 #trivial
  • Ran make next
  • Create 6.5.0 release in changelog (sentry errors were after 6.4.9 submission)
  • Add 6.4.9 to releases in changelog
+24 -19

0 comment

3 changed files

brainbicycle

pr closed time in 2 days

push eventRxSwiftCommunity/rxswiftcommunity.github.io

Ash Furrow (Via Travis)

commit sha 560cbb52570408a20694ca4ffa6406b40a5e9e42

Site updated to 153754b

view details

push time in 2 days

push eventashfurrow/mastodon

Eugen Rochko

commit sha fa3f78e4bf1b5e2b6e8b11f161dd3c02348bf3d4

Fix other sessions not being logged out on password change While OAuth tokens were immediately revoked, accessing the home controller immediately generated new OAuth tokens and "revived" the session due to a combination of using remember_me tokens and overwriting the `authenticate_user!` method

view details

Eugen Rochko

commit sha 951e997b26cb5bf93539a22221efda97ad70079e

Change rate limits for various paths - Rate limit login attempts by target account - Rate limit password resets and e-mail re-confirmations by target account - Rate limit sign-up/login attempts, password resets, and e-mail re-confirmations by IP like before

view details

Thibaut Girka

commit sha 2d2e3651eee12364b53f658077dae9343aca5e09

Fix media attachment enumeration Signed-off-by: Eugen Rochko <eugen@zeonfederated.com>

view details

Eugen Rochko

commit sha 661f3f26b041dd6f1f0ea646e55616f7139bb957

Bump version to 3.1.5

view details

Ash Furrow

commit sha 27a19076ad3413409dbb409eab702734a4836cf6

Merge tag 'v3.1.5'

view details

Ash Furrow

commit sha e3a1b563b7f4aa20d1000b3d74a8daf14566ae59

Updates Docker tag.

view details

push time in 3 days

Pull request review commentartsy/eigen

[WIP] Moving bottom tabs to TS

 - (void)application:(UIApplication *)application performActionForShortcutItem:(U  - (void)openSearch {-    [[ARTopMenuViewController sharedController] showSearch];+    [[ARSwitchBoard sharedInstance] presentViewController:[[ARSwitchBoard sharedInstance] loadPath:@"/search"]]; }  - (void)openFavorites {-    [[ARTopMenuViewController sharedController] showFavs];+    [[ARSwitchBoard sharedInstance] presentViewController:[[ARSwitchBoard sharedInstance] loadPath:@"/favorites"]]; }

Makes sense 👍 Maybe a "consign" action soon too? 🤔

ds300

comment created time in 3 days

Pull request review commentartsy/eigen

[WIP] Moving bottom tabs to TS

 - (void)setupAnalytics     @{         ARAnalyticsTrackedEvents:             @[-                @{-                    ARAnalyticsClass: ARTopMenuViewController.class,-                    ARAnalyticsDetails: @[-                            @{-                                ARAnalyticsEventName: ARAnalyticsProfileView,-                                ARAnalyticsSelectorName: NSStringFromSelector(@selector(tabContentView:didChangeSelectedIndex:)),-                                ARAnalyticsProperties: ^NSDictionary*(ARTopMenuViewController *controller, NSArray *args) {-                                        return @{-                                                 @"tab" : args.count > 1 ? [controller descriptionForNavIndex: [args[1] integerValue]] : @"unknown",-                                             };-                                        }-                                }-                            ]-                    },

Every time this file gets smaller, I smile 😄

ds300

comment created time in 3 days

Pull request review commentartsy/eigen

[WIP] Moving bottom tabs to TS

 - (nullable UIViewController *)previewingContext:(id<UIViewControllerPreviewing>      // Only show visible content, e.g. cropped images by tabs     ARTopMenuViewController *topVC = [ARTopMenuViewController sharedController];-    CGRect visible = CGRectIntersection([cell convertRect:cell.bounds toView:nil], [topVC.tabContentView convertRect:topVC.tabContentView.bounds toView:nil]);+    UIView *cv = (id)topVC.tabContentView;+    +    CGRect visible = CGRectIntersection([cell convertRect:cell.bounds toView:nil], [cv convertRect:cv.bounds toView:nil]);

Once we convert the Auctions view controller from Swift to RN we can finally get rid of this embedded models abstraction 🌟

ds300

comment created time in 3 days

Pull request review commentartsy/eigen

[WIP] Moving bottom tabs to TS

 - (instancetype)initWithEmission:(AREmission *)emission  - (void)viewDidLoad; {-  [super viewDidLoad];-  self.automaticallyAdjustsScrollViewInsets = NO;+    [super viewDidLoad];+    self.automaticallyAdjustsScrollViewInsets = NO; -  self.rootView = [[RCTRootView alloc] initWithBridge:self.emission.bridge+    self.rootView = [[RCTRootView alloc] initWithBridge:self.emission.bridge                                            moduleName:self.moduleName                                     initialProperties:self.initialProperties];-  [self.view addSubview:self.rootView];-  self.rootView.reactViewController = self;--  // We use AutoLayout to ensure the RCTView covers the whole view-  self.rootView.translatesAutoresizingMaskIntoConstraints = NO;--  // Most of the time we want to respect the 'safe area' positioning provided by the-  // OS, but in the cases where we have full bleed headers whiich should go behind-  // the status bar, then the top layout constrain will need to work with the main-  // view instead of the traditional topLayoutGuide-  id topConstrainedItem = (id)self.view;-  NSLayoutAttribute topConstrainedAttribute = NSLayoutAttributeTop;--  [self.view addConstraints:@[-    [NSLayoutConstraint constraintWithItem:self.rootView-                                 attribute:NSLayoutAttributeTop-                                 relatedBy:NSLayoutRelationEqual-                                    toItem:topConstrainedItem-                                 attribute:topConstrainedAttribute-                                multiplier:1-                                  constant:0],-    [NSLayoutConstraint constraintWithItem:self.rootView-                                 attribute:NSLayoutAttributeLeading-                                 relatedBy:NSLayoutRelationEqual-                                    toItem:self.view-                                 attribute:NSLayoutAttributeLeading-                                multiplier:1-                                  constant:0],-    [NSLayoutConstraint constraintWithItem:self.rootView-                                 attribute:NSLayoutAttributeTrailing-                                 relatedBy:NSLayoutRelationEqual-                                    toItem:self.view-                                 attribute:NSLayoutAttributeTrailing-                                multiplier:1-                                  constant:0],-    [NSLayoutConstraint constraintWithItem:self.rootView-                                 attribute:NSLayoutAttributeBottom-                                 relatedBy:NSLayoutRelationEqual-                                    toItem:self.bottomLayoutGuide-                                 attribute:NSLayoutAttributeTop-                                multiplier:1-                                  constant:0]-  ]];+    [self.view addSubview:self.rootView];+    self.rootView.reactViewController = self;++    // We use AutoLayout to ensure the RCTView covers the whole view+    self.rootView.translatesAutoresizingMaskIntoConstraints = NO;++    [self.rootView alignToView:self.view];

🙌

ds300

comment created time in 3 days

Pull request review commentartsy/eigen

[WIP] Moving bottom tabs to TS

   @interface ARTopMenuNavigationDataSource ()--@property (nonatomic, assign, readwrite) NSInteger currentIndex;-@property (nonatomic, assign, readonly) NSUInteger *badgeCounts;--@property (readonly, nonatomic, strong) ArtsyEcho *echo;--@property (readonly, nonatomic, strong) ARNavigationController *feedNavigationController;-@property (nonatomic, strong) ARNavigationController *searchNavigationController;-@property (nonatomic, strong) ARNavigationController *favoritesNavigationController;-@property (nonatomic, strong) ARNavigationController *localDiscoveryNavigationController;-@property (nonatomic, strong) ARNavigationController *messagingNavigationController;-@property (nonatomic, strong) ARNavigationController *profileNavigationController;-@property (nonatomic, strong) ARNavigationController *salesNavigationController;- @end  @implementation ARTopMenuNavigationDataSource -- (void)dealloc;-{-    free(_badgeCounts);-}--- (instancetype)init-{-    self = [super init];--    _echo = [[ArtsyEcho alloc] init];--    _badgeCounts = malloc(sizeof(NSUInteger) * self.tabOrder.count);-    for (int i = 0; i < self.tabOrder.count; i++) {-        _badgeCounts[i] = 0;-    }--    ARHomeComponentViewController *homeVC = [[ARHomeComponentViewController alloc] init];-    _feedNavigationController = [[ARNavigationController alloc] initWithRootViewController:homeVC];--    return self;-}---- (ARNavigationController *)salesNavigationController-{-    if (_salesNavigationController) {-        return _salesNavigationController;-    }--    ARSalesComponentViewController *salesVC = [[ARSalesComponentViewController alloc] init];-    _salesNavigationController = [[ARNavigationController alloc] initWithRootViewController:salesVC];-    return _salesNavigationController;-}--- (ARNavigationController *)searchNavigationController-{-    if (_searchNavigationController) {-        return _searchNavigationController;-    }--    ARSearchComponentViewController *searchVC = [[ARSearchComponentViewController alloc] init];-    _searchNavigationController = [[ARNavigationController alloc] initWithRootViewController:searchVC];-    return _searchNavigationController;-}--- (ARNavigationController *)messagingNavigationController-{-    if (_messagingNavigationController) {-        return _messagingNavigationController;-    }--    ARInboxComponentViewController *messagingVC = [[ARInboxComponentViewController alloc] initWithInbox];-    _messagingNavigationController = [[ARNavigationController alloc] initWithRootViewController:messagingVC];-    return _messagingNavigationController;-}--- (ARNavigationController *)localDiscoveryNavigationController-{-    if (_localDiscoveryNavigationController) {-        return _localDiscoveryNavigationController;-    }--    AREigenMapContainerViewController *mapVC = [[AREigenMapContainerViewController alloc] init];-    _localDiscoveryNavigationController = [[ARNavigationController alloc] initWithRootViewController:mapVC];-    return _localDiscoveryNavigationController;-}--- (ARNavigationController *)profileNavigationController-{-    if (_profileNavigationController) {-        return _profileNavigationController;-    }--    ARMyProfileComponentViewController *profileVC = [[ARMyProfileComponentViewController alloc] init];-    _profileNavigationController = [[ARNavigationController alloc] initWithRootViewController:profileVC];-    return _profileNavigationController;-}--- (ARNavigationController *)favoritesNavigationController-{-    ARFavoritesComponentViewController *favoritesVC = [[ARFavoritesComponentViewController alloc] init];-    _favoritesNavigationController = [[ARNavigationController alloc] initWithRootViewController:favoritesVC];-    return _favoritesNavigationController;-}--- (ARNavigationController *)navigationControllerAtTab:(ARTopTabControllerTabType)tabType;+- (ARNavigationController * (^)(void)) memoize:(UIViewController * (^)(void))constructor {-    switch (tabType) {-        case ARHomeTab:-            return self.feedNavigationController;-        case ARSearchTab:-            return self.searchNavigationController;-        case ARMessagingTab:-            return self.messagingNavigationController;-        case ARLocalDiscoveryTab:-            return self.localDiscoveryNavigationController;-        case ARFavoritesTab:-            return self.favoritesNavigationController;-        case ARSalesTab:-            return self.salesNavigationController;-        case ARMyProfileTab:-            return self.profileNavigationController;-        default:-            return nil;-    }-}--- (ARNavigationController *)navigationControllerAtIndex:(NSInteger)index;-{-    NSInteger tab = [self tabTypeForIndex:index];-    return [self navigationControllerAtTab:tab];-}--# pragma mark Analytics--- (NSString *)analyticsDescriptionForTabAtIndex:(NSInteger)index {-    ARTopTabControllerTabType tab = [self tabTypeForIndex:index];-    switch (tab) {-        case ARHomeTab:-            return @"home";-        case ARSearchTab:-            return @"search";-        case ARMessagingTab:-            return @"messages";-        case ARLocalDiscoveryTab:-            return @"cityGuide";-        case ARFavoritesTab:-            return @"favorites";-        case ARSalesTab:-            return @"sell";-        case ARMyProfileTab:-            // TODO: check with mike what this should be-            return @"profile";-        default:-            return @"unknown";-    }-}--- (NSArray *)tabOrder-{-    BOOL shouldShowSalesTab = [[ARSwitchBoard sharedInstance] isFeatureEnabled:AROptionsEnableSales];--    if ([UIDevice isPhone]) {-        NSMutableArray *iPhoneTabOrder = @[-            @(ARHomeTab),-            @(ARSearchTab),-            @(ARMessagingTab),-            @([AROptions boolForOption:AROptionsEnableNewProfileTab] ? ARMyProfileTab : ARFavoritesTab)-        ].mutableCopy;--        if (shouldShowSalesTab) {-            [iPhoneTabOrder insertObject:@(ARSalesTab) atIndex:3];-        } else {-            [iPhoneTabOrder insertObject:@(ARLocalDiscoveryTab) atIndex:2];+    __block ARNavigationController* result = nil;+    return ^() {+        if (result) {+            return result;         }--        return iPhoneTabOrder;-    } else {-        NSMutableArray *iPadTabOrder = @[-           @(ARHomeTab),-           @(ARSearchTab),-           @(ARMessagingTab),-           @([AROptions boolForOption:AROptionsEnableNewProfileTab] ? ARMyProfileTab : ARFavoritesTab)-        ].mutableCopy;--        if (shouldShowSalesTab) {-            [iPadTabOrder insertObject:@(ARSalesTab) atIndex:3];-        }--        return iPadTabOrder;-    }-}--- (ARTopTabControllerTabType)tabTypeForIndex:(NSInteger)index-{-    return (ARTopTabControllerTabType) [self.tabOrder[index] integerValue];-}--- (NSUInteger)indexForTabType:(ARTopTabControllerTabType)tabType-{-    return [self.tabOrder indexOfObject:@(tabType)];-}--- (NSString *)tabNameForIndex:(NSInteger)index-{-    ARTopTabControllerTabType tab = [self tabTypeForIndex:index];-    switch (tab) {-        case ARHomeTab:-            return @"ARHomeTab";-        case ARSearchTab:-            return @"ARSearchTab";-        case ARMessagingTab:-            return @"ARMessagingTab";-        case ARLocalDiscoveryTab:-            return @"ARLocalDiscoveryTab";-        case ARFavoritesTab:-            return @"ARFavoritesTab";-        case ARSalesTab:-            return @"ARSalesTab";-        case ARMyProfileTab:-            return @"ARMyProfileTab";-        default:-            return @"Unknown";-    }+        result = [[ARNavigationController alloc] initWithRootViewController:constructor()];+        return result;+    }; } -#pragma mark ARTabViewDataSource--- (UINavigationController *)viewControllerForTabContentView:(ARTabContentView *)tabContentView atIndex:(NSInteger)index+- (NSDictionary<NSNumber*, NSDictionary*> *)config

Since this is a property accessor, this function will get ran every time self.config is called. Maybe we want to store this in an ivar, so that it's only created once?

ds300

comment created time in 3 days

Pull request review commentartsy/eigen

[WIP] Moving bottom tabs to TS

   @interface ARTopMenuNavigationDataSource ()--@property (nonatomic, assign, readwrite) NSInteger currentIndex;-@property (nonatomic, assign, readonly) NSUInteger *badgeCounts;--@property (readonly, nonatomic, strong) ArtsyEcho *echo;--@property (readonly, nonatomic, strong) ARNavigationController *feedNavigationController;-@property (nonatomic, strong) ARNavigationController *searchNavigationController;-@property (nonatomic, strong) ARNavigationController *favoritesNavigationController;-@property (nonatomic, strong) ARNavigationController *localDiscoveryNavigationController;-@property (nonatomic, strong) ARNavigationController *messagingNavigationController;-@property (nonatomic, strong) ARNavigationController *profileNavigationController;-@property (nonatomic, strong) ARNavigationController *salesNavigationController;- @end  @implementation ARTopMenuNavigationDataSource -- (void)dealloc;-{-    free(_badgeCounts);-}--- (instancetype)init-{-    self = [super init];--    _echo = [[ArtsyEcho alloc] init];--    _badgeCounts = malloc(sizeof(NSUInteger) * self.tabOrder.count);-    for (int i = 0; i < self.tabOrder.count; i++) {-        _badgeCounts[i] = 0;-    }--    ARHomeComponentViewController *homeVC = [[ARHomeComponentViewController alloc] init];-    _feedNavigationController = [[ARNavigationController alloc] initWithRootViewController:homeVC];--    return self;-}---- (ARNavigationController *)salesNavigationController-{-    if (_salesNavigationController) {-        return _salesNavigationController;-    }--    ARSalesComponentViewController *salesVC = [[ARSalesComponentViewController alloc] init];-    _salesNavigationController = [[ARNavigationController alloc] initWithRootViewController:salesVC];-    return _salesNavigationController;-}--- (ARNavigationController *)searchNavigationController-{-    if (_searchNavigationController) {-        return _searchNavigationController;-    }--    ARSearchComponentViewController *searchVC = [[ARSearchComponentViewController alloc] init];-    _searchNavigationController = [[ARNavigationController alloc] initWithRootViewController:searchVC];-    return _searchNavigationController;-}--- (ARNavigationController *)messagingNavigationController-{-    if (_messagingNavigationController) {-        return _messagingNavigationController;-    }--    ARInboxComponentViewController *messagingVC = [[ARInboxComponentViewController alloc] initWithInbox];-    _messagingNavigationController = [[ARNavigationController alloc] initWithRootViewController:messagingVC];-    return _messagingNavigationController;-}--- (ARNavigationController *)localDiscoveryNavigationController-{-    if (_localDiscoveryNavigationController) {-        return _localDiscoveryNavigationController;-    }--    AREigenMapContainerViewController *mapVC = [[AREigenMapContainerViewController alloc] init];-    _localDiscoveryNavigationController = [[ARNavigationController alloc] initWithRootViewController:mapVC];-    return _localDiscoveryNavigationController;-}--- (ARNavigationController *)profileNavigationController-{-    if (_profileNavigationController) {-        return _profileNavigationController;-    }--    ARMyProfileComponentViewController *profileVC = [[ARMyProfileComponentViewController alloc] init];-    _profileNavigationController = [[ARNavigationController alloc] initWithRootViewController:profileVC];-    return _profileNavigationController;-}--- (ARNavigationController *)favoritesNavigationController-{-    ARFavoritesComponentViewController *favoritesVC = [[ARFavoritesComponentViewController alloc] init];-    _favoritesNavigationController = [[ARNavigationController alloc] initWithRootViewController:favoritesVC];-    return _favoritesNavigationController;-}--- (ARNavigationController *)navigationControllerAtTab:(ARTopTabControllerTabType)tabType;+- (ARNavigationController * (^)(void)) memoize:(UIViewController * (^)(void))constructor {-    switch (tabType) {-        case ARHomeTab:-            return self.feedNavigationController;-        case ARSearchTab:-            return self.searchNavigationController;-        case ARMessagingTab:-            return self.messagingNavigationController;-        case ARLocalDiscoveryTab:-            return self.localDiscoveryNavigationController;-        case ARFavoritesTab:-            return self.favoritesNavigationController;-        case ARSalesTab:-            return self.salesNavigationController;-        case ARMyProfileTab:-            return self.profileNavigationController;-        default:-            return nil;-    }-}--- (ARNavigationController *)navigationControllerAtIndex:(NSInteger)index;-{-    NSInteger tab = [self tabTypeForIndex:index];-    return [self navigationControllerAtTab:tab];-}--# pragma mark Analytics--- (NSString *)analyticsDescriptionForTabAtIndex:(NSInteger)index {-    ARTopTabControllerTabType tab = [self tabTypeForIndex:index];-    switch (tab) {-        case ARHomeTab:-            return @"home";-        case ARSearchTab:-            return @"search";-        case ARMessagingTab:-            return @"messages";-        case ARLocalDiscoveryTab:-            return @"cityGuide";-        case ARFavoritesTab:-            return @"favorites";-        case ARSalesTab:-            return @"sell";-        case ARMyProfileTab:-            // TODO: check with mike what this should be-            return @"profile";-        default:-            return @"unknown";-    }-}--- (NSArray *)tabOrder-{-    BOOL shouldShowSalesTab = [[ARSwitchBoard sharedInstance] isFeatureEnabled:AROptionsEnableSales];--    if ([UIDevice isPhone]) {-        NSMutableArray *iPhoneTabOrder = @[-            @(ARHomeTab),-            @(ARSearchTab),-            @(ARMessagingTab),-            @([AROptions boolForOption:AROptionsEnableNewProfileTab] ? ARMyProfileTab : ARFavoritesTab)-        ].mutableCopy;--        if (shouldShowSalesTab) {-            [iPhoneTabOrder insertObject:@(ARSalesTab) atIndex:3];-        } else {-            [iPhoneTabOrder insertObject:@(ARLocalDiscoveryTab) atIndex:2];+    __block ARNavigationController* result = nil;+    return ^() {+        if (result) {+            return result;

~I'm not sure this is actually memoizing this. result is on the stack frame and will be a fresh value every time it gets called, I think?~ Oh I see, since we're storing the return value (a block) inside a dictionary, the block keeps the stack frame variable in scope and keeps it around. Nice!

ds300

comment created time in 3 days

Pull request review commentartsy/eigen

[WIP] Moving bottom tabs to TS

   @interface ARTopMenuNavigationDataSource ()--@property (nonatomic, assign, readwrite) NSInteger currentIndex;-@property (nonatomic, assign, readonly) NSUInteger *badgeCounts;--@property (readonly, nonatomic, strong) ArtsyEcho *echo;--@property (readonly, nonatomic, strong) ARNavigationController *feedNavigationController;-@property (nonatomic, strong) ARNavigationController *searchNavigationController;-@property (nonatomic, strong) ARNavigationController *favoritesNavigationController;-@property (nonatomic, strong) ARNavigationController *localDiscoveryNavigationController;-@property (nonatomic, strong) ARNavigationController *messagingNavigationController;-@property (nonatomic, strong) ARNavigationController *profileNavigationController;-@property (nonatomic, strong) ARNavigationController *salesNavigationController;- @end  @implementation ARTopMenuNavigationDataSource -- (void)dealloc;-{-    free(_badgeCounts);-}--- (instancetype)init-{-    self = [super init];--    _echo = [[ArtsyEcho alloc] init];--    _badgeCounts = malloc(sizeof(NSUInteger) * self.tabOrder.count);-    for (int i = 0; i < self.tabOrder.count; i++) {-        _badgeCounts[i] = 0;-    }

😱 Sometimes I find code in Eigen and I feel horrified – glad this is going away!

ds300

comment created time in 3 days

Pull request review commentartsy/eigen

[WIP] Moving bottom tabs to TS

 - (void)application:(UIApplication *)application performActionForShortcutItem:(U  - (void)openSearch {-    [[ARTopMenuViewController sharedController] showSearch];+    [[ARSwitchBoard sharedInstance] presentViewController:[[ARSwitchBoard sharedInstance] loadPath:@"/search"]]; }  - (void)openFavorites {-    [[ARTopMenuViewController sharedController] showFavs];+    [[ARSwitchBoard sharedInstance] presentViewController:[[ARSwitchBoard sharedInstance] loadPath:@"/favorites"]]; }

These both power the home screen shortcuts:

<details> <summary>screenshot</summary>

IMG_043237C33CFC-1

</details>

Right now we only have shortcuts for favourites and search. This is unrelated to this PR, but what other areas of the app might we want to provide quick access to? /cc @samchieng

ds300

comment created time in 3 days

issue commentartsy/eigen

[RFC] Pull Requests Template

keep it simple, at least for the first version

Yeah I like this idea quite a bit. I would say even simpler would be a good idea, especially since we use tooling like Peril/Danger to test for things like "have you added unit tests?"

How about something like:

# Introduction

The type of this PR is:

eg. Enhancement

This PR resolves #

Here's what it looks like:

<!-- add screenshots if applicable -->

## Description

Implementation description

## Test Plan

<!-- if necessary -->

MounirDhahri

comment created time in 3 days

push eventRxSwiftCommunity/rxswiftcommunity.github.io

Ash Furrow (Via Travis)

commit sha 6f0676f0e278e08c7a39bfb9abeabe5249003c5c

Site updated to 153754b

view details

push time in 3 days

push eventRxSwiftCommunity/rxswiftcommunity.github.io

Ash Furrow (Via Travis)

commit sha 29bf70e943cb3e53ab7b93c70c6786fb01397131

Site updated to 153754b

view details

push time in 4 days

push eventRxSwiftCommunity/rxswiftcommunity.github.io

Ash Furrow (Via Travis)

commit sha b5f64fa99435f445a9cde3462f49e6415975d991

Site updated to 153754b

view details

push time in 5 days

push eventashfurrow/xcode-hardware-performance

Ash Furrow

commit sha 4639aa25fb1b883ef553ea68c2f93d0e0d04af08

Removes plea for DTK results. I've since learned that the DTK can only compile and run software for macOS (and not iOS). So it can't be included in these benchmarks :sob:

view details

push time in 6 days

push eventRxSwiftCommunity/rxswiftcommunity.github.io

Ash Furrow (Via Travis)

commit sha 6a4ff5a9d9537dbcf158581ec42d9234249094cc

Site updated to 153754b

view details

push time in 6 days

delete branch orta/cocoapods-keys

delete branch : fix-ci

delete time in 6 days

push eventorta/cocoapods-keys

Ash Furrow

commit sha 01c8d686a81625760582c2eea4a8fdfedaf21cba

Ignores gem files.

view details

Ash Furrow

commit sha 3ffd19c0cd7b82594c653d4966a2a8efaadf9cd1

Fixes link URL.

view details

Ash Furrow

commit sha 136529b9e08d1608d9b5fca157dc66fe606db96a

Updates bundle.

view details

Ash Furrow

commit sha 4153cfc7621a89c7ae3f96bb0285d9602f41e267

Merge pull request #206 from orta/fix-ci Fixes CI #trivial

view details

push time in 6 days

PR merged orta/cocoapods-keys

Fixes CI #trivial

This is mostly just running bundle install to update the Gemfile.lock file (example failing build). Also did some cleanup.

This is trivial, so I'm going to self-assign.

+7 -6

0 comment

3 changed files

ashfurrow

pr closed time in 6 days

pull request commentorta/cocoapods-keys

Bump rake from 12.0.0 to 13.0.1

@dependabot ignore this major version

dependabot[bot]

comment created time in 6 days

delete branch orta/cocoapods-keys

delete branch : dependabot/bundler/rake-13.0.1

delete time in 6 days

PR closed orta/cocoapods-keys

Bump rake from 12.0.0 to 13.0.1 dependencies

Bumps rake from 12.0.0 to 13.0.1. <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/ruby/rake/blob/master/History.rdoc">rake's changelog</a>.</em></p> <blockquote> <p>=== 13.0.1</p> <p>==== Bug fixes</p> <ul> <li>Fixed bug: Reenabled task raises previous exception on second invokation Pull Request <a href="https://github-redirect.dependabot.com/ruby/rake/issues/271">#271</a> by thorsteneckel</li> <li>Fix an incorrectly resolved arg pattern Pull Request <a href="https://github-redirect.dependabot.com/ruby/rake/issues/327">#327</a> by mjbellantoni</li> </ul> <p>=== 13.0.0</p> <p>==== Enhancements</p> <ul> <li>Follows recent changes on keyword arguments in ruby 2.7. Pull Request <a href="https://github-redirect.dependabot.com/ruby/rake/issues/326">#326</a> by nobu</li> <li>Make <code>PackageTask</code> be able to omit parent directory while packing files Pull Request <a href="https://github-redirect.dependabot.com/ruby/rake/issues/310">#310</a> by tonytonyjan</li> <li>Add order only dependency Pull Request <a href="https://github-redirect.dependabot.com/ruby/rake/issues/269">#269</a> by take-cheeze</li> </ul> <p>==== Compatibility changes</p> <ul> <li>Drop old ruby versions(< 2.2)</li> </ul> <p>=== 12.3.3</p> <p>==== Bug fixes</p> <ul> <li>Use the application's name in error message if a task is not found. Pull Request <a href="https://github-redirect.dependabot.com/ruby/rake/issues/303">#303</a> by tmatilai</li> </ul> <p>==== Enhancements:</p> <ul> <li>Use File.open explicitly.</li> </ul> <p>=== 12.3.2</p> <p>==== Bug fixes</p> <ul> <li>Fixed test fails caused by 2.6 warnings. Pull Request <a href="https://github-redirect.dependabot.com/ruby/rake/issues/297">#297</a> by hsbt</li> </ul> <p>==== Enhancements:</p> <ul> <li>Rdoc improvements. Pull Request <a href="https://github-redirect.dependabot.com/ruby/rake/issues/293">#293</a> by colby-swandale</li> <li>Improve multitask performance. Pull Request <a href="https://github-redirect.dependabot.com/ruby/rake/issues/273">#273</a> by jsm</li> <li>Add alias <code>prereqs</code>. Pull Request <a href="https://github-redirect.dependabot.com/ruby/rake/issues/268">#268</a> by take-cheeze</li> </ul> <!-- raw HTML omitted --> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/ruby/rake/commit/c8251e2299616d8126e4ac7426e0bb87df7e6922"><code>c8251e2</code></a> Bump version to 13.0.1</li> <li><a href="https://github.com/ruby/rake/commit/8edd860cd0fc9035bda472ef45110a40889b9627"><code>8edd860</code></a> Fixed build failure of the latest GitHub Actions</li> <li><a href="https://github.com/ruby/rake/commit/b6e2a66689e7ac2f39597283dc2276bd082fa279"><code>b6e2a66</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/ruby/rake/issues/271">#271</a> from thorsteneckel/bugfix-reenable_invocation_exception</li> <li><a href="https://github.com/ruby/rake/commit/985abffa9954d21790831d9626d9c38b24a94199"><code>985abff</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/ruby/rake/issues/327">#327</a> from mjbellantoni/mjb-order-only-arg-fix</li> <li><a href="https://github.com/ruby/rake/commit/4a90acb8923f0ea1f7acf50b8d529281a56f170d"><code>4a90acb</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/ruby/rake/issues/329">#329</a> from jeremyevans/skip-taint-test-on-2.7</li> <li><a href="https://github.com/ruby/rake/commit/4dc6282eb24c0117a012d07744ea1bbcae1b3a79"><code>4dc6282</code></a> Skip a taint test on Ruby 2.7</li> <li><a href="https://github.com/ruby/rake/commit/a08b6975a5568799e1d053b7c56ef40d28528d97"><code>a08b697</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/ruby/rake/issues/328">#328</a> from orien/gem-metadata</li> <li><a href="https://github.com/ruby/rake/commit/c3953d4b2935895e1bb4596c435653d3a865711a"><code>c3953d4</code></a> Add project metadata to the gemspec</li> <li><a href="https://github.com/ruby/rake/commit/46a8f7cbd4072431eb16e8e0858d556797ce677e"><code>46a8f7c</code></a> Update comments to reflect the current state</li> <li><a href="https://github.com/ruby/rake/commit/00aacdcf70309a17de2580fb380ed29f2d0fb6f7"><code>00aacdc</code></a> Fix an incorrectly resolved arg pattern</li> <li>Additional commits viewable in <a href="https://github.com/ruby/rake/compare/v12.0.0...v13.0.1">compare view</a></li> </ul> </details> <br />

Dependabot compatibility score

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


<details> <summary>Dependabot commands and options</summary> <br />

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot merge will merge this PR after your CI passes on it
  • @dependabot squash and merge will squash and merge this PR after your CI passes on it
  • @dependabot cancel merge will cancel a previously requested merge and block automerging
  • @dependabot reopen will reopen this PR if it is closed
  • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
  • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
  • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
  • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
  • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

You can disable automated security fix PRs for this repo from the Security Alerts page.

</details>

+1 -1

0 comment

1 changed file

dependabot[bot]

pr closed time in 6 days

PR opened orta/cocoapods-keys

Fixes CI #trivial

This is mostly just running bundle install to update the Gemfile.lock file (example failing build). Also did some cleanup.

This is trivial, so I'm going to self-assign.

+7 -6

0 comment

3 changed files

pr created time in 6 days

create barnchorta/cocoapods-keys

branch : fix-ci

created branch time in 6 days

pull request commentorta/cocoapods-keys

Fix Keys.m generation when there are empty-string keys

Thank you @orta :bow:

Alrighty! Thanks again @rogerluan – I've pushed that as version 2.2.1 to RubyGems. Please get in touch if you find any other issues!

rogerluan

comment created time in 6 days

created tagorta/cocoapods-keys

tagv2.2.1

A key value store for storing per-developer environment and application keys

created time in 6 days

push eventRxSwiftCommunity/rxswiftcommunity.github.io

Ash Furrow (Via Travis)

commit sha 552ecabe901ca80594d6242deff38508eb228b94

Site updated to 153754b

view details

push time in 7 days

PR opened artsy/eigen

[MX-395] Privacy Request visual tweaks

Screen Shot 2020-07-02 at 4 13 32 PM

+2 -2

0 comment

1 changed file

pr created time in 8 days

push eventartsy/eigen

Ash Furrow

commit sha 85edf46a73b842e290d30326079e06981677dfdd

[MX-395] Privacy Request visual tweaks.

view details

push time in 8 days

pull request commentorta/cocoapods-keys

Fix Keys.m generation when there are empty-string keys

Awesome! @orta would you like to add me as an owner to the gem in RubyGems.org and I can handle publishing?

rogerluan

comment created time in 8 days

push eventorta/cocoapods-keys

Roger Oba

commit sha 841ac9a04e81333e2fca69a3eb22a172162756b7

Fix Keys.m generation when there are empty-string keys.

view details

Roger Oba

commit sha ac35e319c7f57ebb2bd7386643cb6cda8ff795a2

Release v2.2.1

view details

Ash Furrow

commit sha 157e3431b73c78ce93434e5e74df32ee92526315

Merge pull request #204 from rogerluan/master Fix Keys.m generation when there are empty-string keys

view details

push time in 8 days

issue closedorta/cocoapods-keys

ZillyKeys.m doesn't compile with "Expected expression" error

After adding gem rake to our Gemfile and upgrading fastlane from 2.150.0rc1 to 2.150.0, it stopped compiling when the key is an empty string "":

image

Removing the extra highlighted comma fixes the compilation issue.

It works fine if the key is not an empty string (but we require this empty string key in our current environment).

I know rake and fastlane are not directly related to this pod, but I'm just trying to provide more information that could help debugging this issue. There are other fastlane dependencies that were upgraded in release 2.150.0.

closed time in 8 days

rogerluan

create barnchartsy/eigen

branch : privacy-tweaks

created branch time in 8 days

issue commentorta/cocoapods-keys

ZillyKeys.m doesn't compile with "Expected expression" error

I see, gotcha. We should add that check back in for zero-length key values. Can you send a PR? Note that #202 fixed some security-related issues, and I would highly highly recommend not to use the older version.

rogerluan

comment created time in 8 days

push eventartsy/eigen

Renovate Bot

commit sha 1c0f3393861411502da7f0049256806eed86c539

Update dep typescript from 3.9.5 to v3.9.6

view details

Ash Furrow

commit sha 1336648c5d817df281ca349c01df3da16e9fddcd

Left-aligns BMW sponsorship.

view details

Ash Furrow

commit sha a3ff535711f7b4e806e683a3bdccb4cf44d6c8fd

Moves to new BMW logo. This was originally done here: https://github.com/artsy/eigen/pull/3203 And it was accidentally reverted here: https://github.com/artsy/eigen/pull/3480

view details

Renovate Bot

commit sha f16da6529aa67794d156f2e0c7acd0fde58e5f22

Update dep @artsy/cohesion from 1.16.0 to v1.17.0

view details

Ash Furrow

commit sha 5cb159e6f42a5e33303aae638b8482ab36c48270

Merge pull request #3520 from artsy/renovate/artsy-cohesion-1.x Update dep @artsy/cohesion from 1.16.0 to v1.17.0

view details

Brian Beckerle

commit sha c6412a5df80adfc088efc3705a4e7d175cf1c6ef

Merge branch 'master' into bmw-tweaks

view details

Ashley Jelks

commit sha 0b2a8d144e10fb625346ee54db3c73ae45d8adc6

Adds artist series query renderer + admin entry point

view details

Anandaroop Roy

commit sha 66040206f8c55b962eb8a9ab582ba186da7e1f08

Remove duplicate artist series vc references Co-authored-by: Brian Beckerle <brian.beckerle@artsymail.com>

view details

Anandaroop Roy

commit sha 583c5a5a02af99225b8a0c60c56cbf4be1439fc1

Create rudimentary layout for Artist Series Co-authored-by: Ashley Jelks <arjelks@gmail.com>

view details

artsy-peril[bot]

commit sha 22fb4ddd91a8c1465a43fe6ff76c6fc987885ece

[MX-380] Tweaks to BMW sponsorship #trivial (#3519) [MX-380] Tweaks to BMW sponsorship #trivial

view details

Sarah Weir

commit sha 8389a578b556a9e634035179eeaf0581d09d46fd

Merge branch 'master' into artist-series-entry-pt

view details

Anandaroop Roy

commit sha 057fdeb8c46c80e5720482de8721d0fb5f47a950

Merge pull request #3516 from artsy/artist-series-entry-pt Adds Artist Series Entry Point

view details

Renovate Bot

commit sha e98256b5720429427ed9c9c7d4964d2493d6723e

Update dep @artsy/cohesion from 1.17.0 to v1.18.0

view details

artsyit

commit sha b51777ea3df6f972eeecf9b7ae7f481359be166c

Update metaphysics schema

view details

artsy-peril[bot]

commit sha 9b3d6a25ba6a0be71b97a1e71c0c25ee9934f3c4

Update metaphysics schema (#3524) Update metaphysics schema

view details

Ash Furrow

commit sha 19aa0700010ea6fd8fac7df38ca1e71906e84027

[MX-336] Adds tracking for home promo space.

view details

push time in 8 days

Pull request review commentartsy/eigen

Search box in Select modal

+import { normalizeText } from "./normalizeText"++export interface AutocompleteEntry<T> {+  key: T+  searchTerms: string[]+  importance: number+}++export class Autocomplete<T> {+  private cache: Record<string, Array<AutocompleteEntry<T>>> = {}

This is really cool, can we double-check that this runs smoothly on a low-spec iOS device? I can try on my SE, or your iPod Touch would work too (if you haven't yet).

ds300

comment created time in 8 days

Pull request review commentartsy/eigen

Search box in Select modal

+import { Autocomplete, AutocompleteEntry } from "../Autocomplete"++const artists: Array<AutocompleteEntry<string>> = [+  {+    key: "Pablo Picasso",+    importance: 100,+    searchTerms: ["Pablo Picasso"],+  },+  {+    key: "Grayson Perry",+    importance: 10,+    searchTerms: ["Grayson Perry"],+  },+  {+    key: "Prince",+    importance: 50,+    searchTerms: ["Prince", "The artist formerly known as 'Prince'"],+  },+  {+    key: "James Brown",+    importance: 100,+    searchTerms: ["JB", "The King of Funk"],+  },+]

This is cool, and seems like it would be easy to use in the kind of client-side search optimizations you've brought up before (or at least, maybe I'm just primed to think of that given the test fixture). Looks great 🌟

ds300

comment created time in 8 days

Pull request review commentartsy/eigen

Search box in Select modal

+import { Autocomplete, AutocompleteEntry } from "../Autocomplete"++const artists: Array<AutocompleteEntry<string>> = [+  {+    key: "Pablo Picasso",+    importance: 100,+    searchTerms: ["Pablo Picasso"],+  },+  {+    key: "Grayson Perry",+    importance: 10,+    searchTerms: ["Grayson Perry"],+  },+  {+    key: "Prince",+    importance: 50,+    searchTerms: ["Prince", "The artist formerly known as 'Prince'"],+  },+  {+    key: "James Brown",+    importance: 100,+    searchTerms: ["JB", "The King of Funk"],+  },+]++describe(Autocomplete, () => {+  it(`lets you search for individual words in search terms`, async () => {+    const auto = new Autocomplete(artists)+    expect(auto.getSuggestions("formerly")).toEqual(["Prince"])+  })+  it(`doesn't care about capitalization`, async () => {+    const auto = new Autocomplete(artists)+    expect(auto.getSuggestions("fOrMerly")).toEqual(["Prince"])+  })+  it(`doesn't care about punctuation`, async () => {+    const auto = new Autocomplete([+      ...artists,+      {+        key: "Dog",+        importance: +Infinity,+        searchTerms: ["Santa's little helper"],+      },+    ])+    expect(auto.getSuggestions("fOrMerl,y")).toEqual(["Prince"])+    expect(auto.getSuggestions("santas")).toEqual(["Dog"])+  })+  it(`doesn't care about diacritics`, async () => {+    const auto = new Autocomplete([+      ...artists,+      {+        key: "Nordic",+        importance: +Infinity,+        searchTerms: ["Jón Jønssön"],+      },+    ])++    expect(auto.getSuggestions("Jon")).toEqual(["Nordic"])+    expect(auto.getSuggestions("Jonsson")).toEqual(["Nordic"])+  })+  it(`orders results according to importance`, async () => {+    const auto = new Autocomplete(artists)+    expect(auto.getSuggestions("p")).toEqual(["Pablo Picasso", "Prince", "Grayson Perry"])+  })+  it(`returns nothing when there are no matches`, async () => {+    const auto = new Autocomplete(artists)+    expect(auto.getSuggestions("z")).toEqual([])+  })+  it(`ignores stop words which don't appear at the beginning of a search term`, async () => {+    const auto = new Autocomplete(+      [+        ...artists,+        {+          key: "PaRappa the Rapper",+          importance: +Infinity * 2,+          searchTerms: ["PaRappa the Rapper"],+        },+      ],+      10,+      ["the"]+    )+    expect(auto.getSuggestions("the")).toContain("James Brown")+    expect(auto.getSuggestions("the")).not.toContain("PaRappa the Rapper")+    expect(auto.getSuggestions("Rapper")).toEqual(["PaRappa the Rapper"])

🤩

ds300

comment created time in 8 days

Pull request review commentartsy/eigen

Search box in Select modal

 const saveCreditCard = (token: string) => {   }) } -const COUNTRY_SELECT_OPTIONS = [-  { label: "Afghanistan", value: "AF" },-  { label: "Åland Islands", value: "AX" },-  { label: "Albania", value: "AL" },-  { label: "Algeria", value: "DZ" },-  { label: "American Samoa", value: "AS" },-  { label: "Andorra", value: "AD" },-  { label: "Angola", value: "AO" },-  { label: "Anguilla", value: "AI" },-  { label: "Antarctica", value: "AQ" },-  { label: "Antigua and Barbuda", value: "AG" },-  { label: "Argentina", value: "AR" },-  { label: "Armenia", value: "AM" },-  { label: "Aruba", value: "AW" },-  { label: "Australia", value: "AU" },-  { label: "Austria", value: "AT" },-  { label: "Azerbaijan", value: "AZ" },-  { label: "Bahamas", value: "BS" },-  { label: "Bahrain", value: "BH" },-  { label: "Bangladesh", value: "BD" },-  { label: "Barbados", value: "BB" },-  { label: "Belarus", value: "BY" },-  { label: "Belgium", value: "BE" },-  { label: "Belize", value: "BZ" },-  { label: "Benin", value: "BJ" },-  { label: "Bermuda", value: "BM" },-  { label: "Bhutan", value: "BT" },-  { label: "Bolivia", value: "BO" },-  { label: "Bosnia and Herzegovina", value: "BA" },-  { label: "Botswana", value: "BW" },-  { label: "Bouvet Island", value: "BV" },-  { label: "Brazil", value: "BR" },-  { label: "British Indian Ocean Territory", value: "IO" },-  { label: "Brunei Darussalam", value: "BN" },-  { label: "Bulgaria", value: "BG" },-  { label: "Burkina Faso", value: "BF" },-  { label: "Burundi", value: "BI" },-  { label: "Cambodia", value: "KH" },-  { label: "Cameroon", value: "CM" },-  { label: "Canada", value: "CA" },-  { label: "Cape Verde", value: "CV" },-  { label: "Cayman Islands", value: "KY" },-  { label: "Central African Republic", value: "CF" },-  { label: "Chad", value: "TD" },-  { label: "Chile", value: "CL" },-  { label: "China", value: "CN" },-  { label: "Christmas Island", value: "CX" },-  { label: "Cocos (Keeling) Islands", value: "CC" },-  { label: "Colombia", value: "CO" },-  { label: "Comoros", value: "KM" },-  { label: "Congo", value: "CG" },-  { label: "Congo, The Democratic Republic of the", value: "CD" },-  { label: "Cook Islands", value: "CK" },-  { label: "Costa Rica", value: "CR" },-  { label: "Cote D'Ivoire", value: "CI" },-  { label: "Croatia", value: "HR" },-  { label: "Cuba", value: "CU" },-  { label: "Cyprus", value: "CY" },-  { label: "Czech Republic", value: "CZ" },-  { label: "Denmark", value: "DK" },-  { label: "Djibouti", value: "DJ" },-  { label: "Dominica", value: "DM" },-  { label: "Dominican Republic", value: "DO" },-  { label: "Ecuador", value: "EC" },-  { label: "Egypt", value: "EG" },-  { label: "El Salvador", value: "SV" },-  { label: "Equatorial Guinea", value: "GQ" },-  { label: "Eritrea", value: "ER" },-  { label: "Estonia", value: "EE" },-  { label: "Ethiopia", value: "ET" },-  { label: "Falkland Islands (Malvinas)", value: "FK" },-  { label: "Faroe Islands", value: "FO" },-  { label: "Fiji", value: "FJ" },-  { label: "Finland", value: "FI" },-  { label: "France", value: "FR" },-  { label: "French Guiana", value: "GF" },-  { label: "French Polynesia", value: "PF" },-  { label: "French Southern Territories", value: "TF" },-  { label: "Gabon", value: "GA" },-  { label: "Gambia", value: "GM" },-  { label: "Georgia", value: "GE" },-  { label: "Germany", value: "DE" },-  { label: "Ghana", value: "GH" },-  { label: "Gibraltar", value: "GI" },-  { label: "Greece", value: "GR" },-  { label: "Greenland", value: "GL" },-  { label: "Grenada", value: "GD" },-  { label: "Guadeloupe", value: "GP" },-  { label: "Guam", value: "GU" },-  { label: "Guatemala", value: "GT" },-  { label: "Guernsey", value: "GG" },-  { label: "Guinea", value: "GN" },-  { label: "Guinea-Bissau", value: "GW" },-  { label: "Guyana", value: "GY" },-  { label: "Haiti", value: "HT" },-  { label: "Heard Island and Mcdonald Islands", value: "HM" },-  { label: "Holy See (Vatican City State)", value: "VA" },-  { label: "Honduras", value: "HN" },-  { label: "Hong Kong", value: "HK" },-  { label: "Hungary", value: "HU" },-  { label: "Iceland", value: "IS" },-  { label: "India", value: "IN" },-  { label: "Indonesia", value: "ID" },-  { label: "Iran, Islamic Republic Of", value: "IR" },-  { label: "Iraq", value: "IQ" },-  { label: "Ireland", value: "IE" },-  { label: "Isle of Man", value: "IM" },-  { label: "Israel", value: "IL" },-  { label: "Italy", value: "IT" },-  { label: "Jamaica", value: "JM" },-  { label: "Japan", value: "JP" },-  { label: "Jersey", value: "JE" },-  { label: "Jordan", value: "JO" },-  { label: "Kazakhstan", value: "KZ" },-  { label: "Kenya", value: "KE" },-  { label: "Kiribati", value: "KI" },-  { label: "Korea, Democratic People's Republic of", value: "KP" },-  { label: "Korea, Republic of", value: "KR" },-  { label: "Kuwait", value: "KW" },-  { label: "Kyrgyzstan", value: "KG" },-  { label: "Lao People's Democratic Republic", value: "LA" },-  { label: "Latvia", value: "LV" },-  { label: "Lebanon", value: "LB" },-  { label: "Lesotho", value: "LS" },-  { label: "Liberia", value: "LR" },-  { label: "Libyan Arab Jamahiriya", value: "LY" },-  { label: "Liechtenstein", value: "LI" },-  { label: "Lithuania", value: "LT" },-  { label: "Luxembourg", value: "LU" },-  { label: "Macao", value: "MO" },-  { label: "Macedonia, The Former Yugoslav Republic of", value: "MK" },-  { label: "Madagascar", value: "MG" },-  { label: "Malawi", value: "MW" },-  { label: "Malaysia", value: "MY" },-  { label: "Maldives", value: "MV" },-  { label: "Mali", value: "ML" },-  { label: "Malta", value: "MT" },-  { label: "Marshall Islands", value: "MH" },-  { label: "Martinique", value: "MQ" },-  { label: "Mauritania", value: "MR" },-  { label: "Mauritius", value: "MU" },-  { label: "Mayotte", value: "YT" },-  { label: "Mexico", value: "MX" },-  { label: "Micronesia, Federated States of", value: "FM" },-  { label: "Moldova, Republic of", value: "MD" },-  { label: "Monaco", value: "MC" },-  { label: "Mongolia", value: "MN" },-  { label: "Montenegro", value: "ME" },-  { label: "Montserrat", value: "MS" },-  { label: "Morocco", value: "MA" },-  { label: "Mozambique", value: "MZ" },-  { label: "Myanmar", value: "MM" },-  { label: "Namibia", value: "NA" },-  { label: "Nauru", value: "NR" },-  { label: "Nepal", value: "NP" },-  { label: "Netherlands", value: "NL" },-  { label: "Netherlands Antilles", value: "AN" },-  { label: "New Caledonia", value: "NC" },-  { label: "New Zealand", value: "NZ" },-  { label: "Nicaragua", value: "NI" },-  { label: "Niger", value: "NE" },-  { label: "Nigeria", value: "NG" },-  { label: "Niue", value: "NU" },-  { label: "Norfolk Island", value: "NF" },-  { label: "Northern Mariana Islands", value: "MP" },-  { label: "Norway", value: "NO" },-  { label: "Oman", value: "OM" },-  { label: "Pakistan", value: "PK" },-  { label: "Palau", value: "PW" },-  { label: "Palestinian Territory, Occupied", value: "PS" },-  { label: "Panama", value: "PA" },-  { label: "Papua New Guinea", value: "PG" },-  { label: "Paraguay", value: "PY" },-  { label: "Peru", value: "PE" },-  { label: "Philippines", value: "PH" },-  { label: "Pitcairn", value: "PN" },-  { label: "Poland", value: "PL" },-  { label: "Portugal", value: "PT" },-  { label: "Puerto Rico", value: "PR" },-  { label: "Qatar", value: "QA" },-  { label: "Reunion", value: "RE" },-  { label: "Romania", value: "RO" },-  { label: "Russian Federation", value: "RU" },-  { label: "Rwanda", value: "RW" },-  { label: "Saint Helena", value: "SH" },-  { label: "Saint Kitts and Nevis", value: "KN" },-  { label: "Saint Lucia", value: "LC" },-  { label: "Saint Pierre and Miquelon", value: "PM" },-  { label: "Saint Vincent and the Grenadines", value: "VC" },-  { label: "Samoa", value: "WS" },-  { label: "San Marino", value: "SM" },-  { label: "Sao Tome and Principe", value: "ST" },-  { label: "Saudi Arabia", value: "SA" },-  { label: "Senegal", value: "SN" },-  { label: "Serbia", value: "RS" },-  { label: "Seychelles", value: "SC" },-  { label: "Sierra Leone", value: "SL" },-  { label: "Singapore", value: "SG" },-  { label: "Slovakia", value: "SK" },-  { label: "Slovenia", value: "SI" },-  { label: "Solomon Islands", value: "SB" },-  { label: "Somalia", value: "SO" },-  { label: "South Africa", value: "ZA" },-  { label: "South Georgia and the South Sandwich Islands", value: "GS" },-  { label: "Spain", value: "ES" },-  { label: "Sri Lanka", value: "LK" },-  { label: "Sudan", value: "SD" },-  { label: "Suriname", value: "SR" },-  { label: "Svalbard and Jan Mayen", value: "SJ" },-  { label: "Swaziland", value: "SZ" },-  { label: "Sweden", value: "SE" },-  { label: "Switzerland", value: "CH" },-  { label: "Syrian Arab Republic", value: "SY" },-  { label: "Taiwan, Province of China", value: "TW" },-  { label: "Tajikistan", value: "TJ" },-  { label: "Tanzania, United Republic of", value: "TZ" },-  { label: "Thailand", value: "TH" },-  { label: "Timor-Leste", value: "TL" },-  { label: "Togo", value: "TG" },-  { label: "Tokelau", value: "TK" },-  { label: "Tonga", value: "TO" },-  { label: "Trinidad and Tobago", value: "TT" },-  { label: "Tunisia", value: "TN" },-  { label: "Turkey", value: "TR" },-  { label: "Turkmenistan", value: "TM" },-  { label: "Turks and Caicos Islands", value: "TC" },-  { label: "Tuvalu", value: "TV" },-  { label: "Uganda", value: "UG" },-  { label: "Ukraine", value: "UA" },-  { label: "United Arab Emirates", value: "AE" },-  { label: "United Kingdom", value: "GB" },-  { label: "United States", value: "US" },-  { label: "United States Minor Outlying Islands", value: "UM" },-  { label: "Uruguay", value: "UY" },-  { label: "Uzbekistan", value: "UZ" },-  { label: "Vanuatu", value: "VU" },-  { label: "Venezuela", value: "VE" },-  { label: "Viet Nam", value: "VN" },-  { label: "Virgin Islands, British", value: "VG" },-  { label: "Virgin Islands, U.S.", value: "VI" },-  { label: "Wallis and Futuna", value: "WF" },-  { label: "Western Sahara", value: "EH" },-  { label: "Yemen", value: "YE" },-  { label: "Zambia", value: "ZM" },-  { label: "Zimbabwe", value: "ZW" },+const COUNTRY_SELECT_OPTIONS: Array<SelectOption<string>> = [

Where did these come from? Should we reference the source here, and do you think they ought to be in their own file?

ds300

comment created time in 8 days

Pull request review commentartsy/eigen

Search box in Select modal

 import { CheckIcon, CloseIcon, color, Flex, Sans, Separator } from "@artsy/palette"-import React, { useEffect, useRef, useState } from "react"+import { Autocomplete } from "lib/utils/Autocomplete"+import React, { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react" import { Animated, FlatList, TouchableHighlight, TouchableOpacity } from "react-native" import Svg, { Path } from "react-native-svg" // @ts-ignore import TextInputState from "react-native/Libraries/Components/TextInput/TextInputState" import { FancyModal } from "./FancyModal" import { INPUT_HEIGHT } from "./Input/Input"+import { SearchInput } from "./SearchInput"  export interface SelectOption<ValueType> {   value: ValueType   label: NonNullable<React.ReactNode>+  searchTerms?: string[]+  searchImportance?: number }  const ROW_HEIGHT = 40--export function Select<ValueType extends any>({-  options,-  onSelectValue,-  value: _value,-  placeholder,-  title,-}: {+interface SelectProps<ValueType> {   options: Array<SelectOption<ValueType>>   value: ValueType | null   placeholder: string-  title?: string+  title: string   enableSearch?: boolean   onSelectValue(value: ValueType): void-}) {-  // we need to be able to have a local version of the value state so we can show the updated-  // state between the moment the user taps a selection and the moment we automatically-  // close the modal. We don't want to tell the consuming component about the user's selection until the-  // animation is finished, so they don't have to worry about waiting for the animation to finish if they need-  // to trigger further actions as a result.-  const [value, setValue] = useState(_value)-  useEffect(() => {-    setValue(_value)-  }, [_value])+}+interface State {+  showingModal: boolean+}+export class Select<ValueType> extends React.Component<SelectProps<ValueType>, State> {+  state: State = { showingModal: false }++  async open() {+    // tinkering with RN internals here to make sure that when this select is tapped we blur+    // any text input that was focuesd at the time.+    if (TextInputState.currentlyFocusedField()) {+      TextInputState.blurTextInput(TextInputState.currentlyFocusedField())+      await new Promise(r => requestAnimationFrame(r))

Oh that's neat, good find. I appreciate the comment, too 🙇

ds300

comment created time in 8 days

Pull request review commentartsy/eigen

Search box in Select modal

 import LoadingModal from "lib/Components/Modals/LoadingModal" import { PageWithSimpleHeader } from "lib/Components/PageWithSimpleHeader" import SwitchBoard from "lib/NativeModules/SwitchBoard" import React, { useImperativeHandle, useRef, useState } from "react"-import { KeyboardAvoidingView, ScrollView, TouchableOpacity } from "react-native"+import { KeyboardAvoidingView, ScrollView, TouchableOpacity, ViewStyle } from "react-native"  export interface MyAccountFieldEditScreen {   scrollToEnd(): void+  save(): Promise<void> } export const MyAccountFieldEditScreen = React.forwardRef<   { scrollToEnd(): void },-  React.PropsWithChildren<{ title: string; canSave: boolean; onSave(): Promise<any> }>->(({ children, canSave, onSave, title }, ref) => {+  React.PropsWithChildren<{

Oh so that's how one accesses children in a functional component, gotcha.

ds300

comment created time in 8 days

Pull request review commentartsy/eigen

Search box in Select modal

+/*+   Licensed under the Apache License, Version 2.0 (the "License");+   you may not use this file except in compliance with the License.+   You may obtain a copy of the License at++       http://www.apache.org/licenses/LICENSE-2.0++   Unless required by applicable law or agreed to in writing, software+   distributed under the License is distributed on an "AS IS" BASIS,+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+   See the License for the specific language governing permissions and+   limitations under the License.++   THIS CODE TAKEN FROM+   https://stackoverflow.com/a/18391901

Ace 👍

ds300

comment created time in 8 days

Pull request review commentartsy/eigen

Search box in Select modal

+import { Flex, Sans } from "@artsy/palette"+import SearchIcon from "lib/Icons/SearchIcon"+import React, { RefObject, useState } from "react"+import { LayoutAnimation, TextInput, TouchableOpacity } from "react-native"+import { Input, InputProps } from "./Input/Input"++interface SearchInputProps extends InputProps {+  enableCancelButton?: boolean+}++export const SearchInput = React.forwardRef<TextInput, SearchInputProps>(({ enableCancelButton, ...props }, ref) => {+  const [inputFocused, setInputFocused] = useState(false)+  return (+    <Flex flexDirection="row">+      <Input+        ref={ref}+        icon={<SearchIcon width={18} height={18} />}+        autoCorrect={false}+        enableClearButton+        returnKeyType="search"+        {...props}+        onFocus={e => {+          if (enableCancelButton) {+            LayoutAnimation.configureNext({ ...LayoutAnimation.Presets.easeInEaseOut, duration: 180 })+          }+          setInputFocused(true)+          props.onFocus?.(e)+        }}+        onBlur={e => {+          if (enableCancelButton) {+            LayoutAnimation.configureNext({ ...LayoutAnimation.Presets.easeInEaseOut, duration: 180 })+          }+          setInputFocused(false)+          props.onBlur?.(e)+        }}+      />+      {!!enableCancelButton && (+        <Flex alignItems="center" justifyContent="center" flexDirection="row">+          {!!inputFocused && (+            <TouchableOpacity+              onPress={() => {+                ;(ref as RefObject<TextInput>).current?.blur()+              }}+              hitSlop={{ bottom: 40, right: 40, left: 0, top: 40 }}

🙌

ds300

comment created time in 8 days

Pull request review commentartsy/eigen

Search box in Select modal

+import { updateMyUserProfileMutation } from "__generated__/updateMyUserProfileMutation.graphql"+import { defaultEnvironment } from "lib/relay/createEnvironment"+import { commitMutation, graphql } from "react-relay"++export const updateMyUserProfile = async (input: updateMyUserProfileMutation["variables"]["input"]) => {+  await new Promise((resolve, reject) =>+    commitMutation<updateMyUserProfileMutation>(defaultEnvironment, {+      onCompleted: resolve,+      mutation: graphql`+        mutation updateMyUserProfileMutation($input: UpdateMyProfileInput!) {+          updateMyUserProfile(input: $input) {+            me {+              email+              name+              phone+            }+          }+        }+      `,+      variables: {+        input,+      },+      onError: e => {+        // try to ge a user-facing error message+        try {+          const message = JSON.parse(JSON.stringify(e))?.res?.json?.errors?.[0]?.message ?? ""+          // should be like "https://api.artsy.net/api/v1/me?email=david@artsymail.com - {"error": "User-facing error message"}"

👍

ds300

comment created time in 8 days

Pull request review commentartsy/eigen

Search box in Select modal

 import LoadingModal from "lib/Components/Modals/LoadingModal" import { PageWithSimpleHeader } from "lib/Components/PageWithSimpleHeader" import SwitchBoard from "lib/NativeModules/SwitchBoard" import React, { useImperativeHandle, useRef, useState } from "react"-import { KeyboardAvoidingView, ScrollView, TouchableOpacity } from "react-native"+import { KeyboardAvoidingView, ScrollView, TouchableOpacity, ViewStyle } from "react-native"  export interface MyAccountFieldEditScreen {   scrollToEnd(): void+  save(): Promise<void> } export const MyAccountFieldEditScreen = React.forwardRef<   { scrollToEnd(): void },-  React.PropsWithChildren<{ title: string; canSave: boolean; onSave(): Promise<any> }>->(({ children, canSave, onSave, title }, ref) => {+  React.PropsWithChildren<{+    title: string+    canSave: boolean+    contentContainerStyle?: ViewStyle+    onSave(dismiss: () => void): Promise<any>+  }>+>(({ children, canSave, onSave, title, contentContainerStyle }, ref) => {   const [isSaving, setIsSaving] = useState<boolean>(false)   const scrollViewRef = useRef<ScrollView>(null)-  useImperativeHandle(-    ref,-    () => {-      return {-        scrollToEnd() {-          scrollViewRef.current?.scrollToEnd()-        },-      }-    },-    []-  )++  const onDismiss = () => {+    SwitchBoard.dismissNavigationViewController(scrollViewRef.current!)+  }    const handleSave = async () => {     if (!canSave) {       return     }     try {       setIsSaving(true)-      await onSave()+      await onSave(onDismiss)     } catch (e) {       console.error(e)     } finally {       setIsSaving(false)     }   } +  useImperativeHandle(

I kind of get what this is doing, after reading the docs, but maybe we could go over it at a Knowledge Share sometime.

ds300

comment created time in 8 days

issue commentartsy/eigen

[RFC] Pull Requests Template

@adamvert I think an RFC might be a good way to test the waters on how people are feeling about it (see this example of an open-ended RFC discussion). If you're looking for a less structured and synchronous discussion, I can recommend using a Lunch & Learn slot on Thursdays to discuss as well 👍

MounirDhahri

comment created time in 8 days

delete branch artsy/cohesion

delete branch : fix-promo-export

delete time in 8 days

PR opened artsy/cohesion

Adds export for promo space

When I went to use this in Eigen, the new helper wasn't visible. Looks like new files need to be added here.

+1 -0

0 comment

1 changed file

pr created time in 8 days

create barnchartsy/cohesion

branch : fix-promo-export

created branch time in 8 days

PR merged artsy/eigen

Update dep @artsy/cohesion from 1.16.0 to v1.17.0

This PR contains the following updates:

Package Type Update Change
@artsy/cohesion dependencies minor 1.16.0 -> 1.17.0

See full list of changes here.


Release Notes

<details> <summary>artsy/cohesion</summary>

v1.17.0

Compare Source

🚀 Enhancement
🏠 Internal
Authors: 2

</details>


Renovate configuration

:date: Schedule: At any time (no schedule defined).

:vertical_traffic_light: Automerge: Enabled.

:recycle: Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

:no_bell: Ignore: Close this PR and you won't be reminded about this update again.


  • [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

This PR has been generated by WhiteSource Renovate. View repository job log here.

+5 -5

1 comment

2 changed files

renovate[bot]

pr closed time in 8 days

push eventartsy/eigen

Renovate Bot

commit sha f16da6529aa67794d156f2e0c7acd0fde58e5f22

Update dep @artsy/cohesion from 1.16.0 to v1.17.0

view details

Ash Furrow

commit sha 5cb159e6f42a5e33303aae638b8482ab36c48270

Merge pull request #3520 from artsy/renovate/artsy-cohesion-1.x Update dep @artsy/cohesion from 1.16.0 to v1.17.0

view details

push time in 8 days

delete branch artsy/eigen

delete branch : renovate/artsy-cohesion-1.x

delete time in 8 days

delete branch artsy/cohesion

delete branch : promo-space-helper

delete time in 8 days

push eventartsy/eigen

Ash Furrow

commit sha a3ff535711f7b4e806e683a3bdccb4cf44d6c8fd

Moves to new BMW logo. This was originally done here: https://github.com/artsy/eigen/pull/3203 And it was accidentally reverted here: https://github.com/artsy/eigen/pull/3480

view details

push time in 8 days

PR opened artsy/cohesion

Adds helper for promo space tap tracking

See conversation here: https://github.com/artsy/eigen/pull/3517/files#r448654900

+55 -0

0 comment

2 changed files

pr created time in 8 days

create barnchartsy/cohesion

branch : promo-space-helper

created branch time in 8 days

Pull request review commentartsy/eigen

[MX-336] Adds tracking for home promo space #trivial

 const HomeHero: React.FC<{ homePage: HomeHero_homePage }> = ({ homePage }) => {    const { width, height } = useHeroDimensions() +  const handlePromoSpaceTap = () => {+    const path = unit.href!+    const event: TappedPromoSpace = {

I see, thanks. I'll take that on next 👍

ashfurrow

comment created time in 8 days

push eventRxSwiftCommunity/rxswiftcommunity.github.io

Ash Furrow (Via Travis)

commit sha 8c4d1da2af7be2fb015ba13c557ab7787541cd6f

Site updated to 153754b

view details

push time in 8 days

push eventashfurrow/xcode-hardware-performance

Ash Furrow

commit sha a8bc175aaf7ffb9b40285e4d4331c2a682f38e03

Adds a plea for DTK results.

view details

push time in 8 days

issue commentashfurrow/danger-ruby-swiftlint

Skip/remove swiftlint task

Hello! Thank you for the kind words and the informative issue. This change makes sense to me – I would be happy to review a PR adding this feature.

I would recommend adding a new command, rather than augmenting the existing swiftlint.lint_files command with more arguments. Something like swiftlint.process_report, with matching tests. Let me know if I can provide more guidance here – I'm looking forward to seeing what you come up with!

SaezChristopher

comment created time in 8 days

PR opened artsy/eigen

[MX-380] Tweaks to BMW sponsorship #trivial

See the note in the second commit for more info on the logo file churn.

+3 -4

0 comment

5 changed files

pr created time in 9 days

create barnchartsy/eigen

branch : bmw-tweaks

created branch time in 9 days

PR opened artsy/eigen

[MX-336] Adds tracking for home promo space

Not sure if I went overboard on the typings here, open to feedback.

In the Cohesion PR, @eessex mentioned that on the web, we split the URL to calculate these attributes. I took a stab at this, but there are a lot of edge cases and unless we match the web implementation exactly, it will only introduce noise in the data. These attributes can be calculated by the data team based on destination_path, so I didn't add the destination_screen_owner_type, destination_screen_owner_id, or destination_screen_owner_slug attributes. /cc @mikehrom

See: https://github.com/artsy/cohesion/pull/69

+37 -5

0 comment

2 changed files

pr created time in 9 days

push eventartsy/eigen

Ash Furrow

commit sha bd6c98f99f92aac27bd10a14f476a93cd103f2b3

[MX-336] Adds tracking for home promo space.

view details

push time in 9 days

create barnchartsy/eigen

branch : home-promo-space-tracking

created branch time in 9 days

push eventartsy/eigen

David Sheldrick

commit sha 709bfbed804753cedc3ea5abf69a12ec05c90224

set up new page for Payment

view details

David Sheldrick

commit sha 4f8c03262089327a6f5a75d247dd22b549283d7c

add credit card delete mutation

view details

David Sheldrick

commit sha 596aabf8a1842710f0ae405c0faa93d0c02e61a1

apply Sam's Visual QA

view details

David Sheldrick

commit sha f32299244f731fdc0cd605dab7595599bc507dc2

add new card screen

view details

David Sheldrick

commit sha e2fa57b460280197158cd723c377a55274b9c7e7

new credit card form almost there

view details

David Sheldrick

commit sha 05455fb1b8a9cb0da03f3b9361b4a0ffb02b3fa7

add fancy modal component

view details

David Sheldrick

commit sha 92c8edaae194916524762370a9332284bad8d75c

fix home hero spacing

view details

David Sheldrick

commit sha 32098d1144c33ac7be63a7f6bb2fc83f877d5c00

fancy modal max height

view details

David Sheldrick

commit sha 9493274036ad0d10c564796841d840b23eb3849f

page with simple header alignment improvment

view details

David Sheldrick

commit sha 593fdb2a0f4f290469a4239d0f1125c0b904a339

add Select component using FancyModal

view details

David Sheldrick

commit sha 15de7973ca9e4c7fbaf17bc080222104aa058a07

Merge remote-tracking branch 'origin/master' into profile-payment

view details

David Sheldrick

commit sha 192b3090d65c62ffd521e715256831722207156c

custom arrow for Select from sam

view details

David Sheldrick

commit sha 37a501e34cc884dc72217bfa426b5b32c4acf10a

tokenize and save card

view details

David Sheldrick

commit sha f00b167be7c23ba89c3a10a30c122b87945f405b

add comments for FancyModal

view details

David Sheldrick

commit sha c371617657eaef088a1871eb65c52ca948638e24

remove react-native-modal since we aren't using it anywhere

view details

David Sheldrick

commit sha d8a99ad1164d5c0e059edb8d4c0bbf8a75be2c47

add comments for Select

view details

David Sheldrick

commit sha e25403fb6fccc6f123db7faa4a3c5f1a97e91838

add credit for useInterval

view details

David Sheldrick

commit sha 145ee7247bb7cd171d40111e69c765a916fa1351

fix tests

view details

David Sheldrick

commit sha aa774bca4e5cc5c17ec04c50e427506e0858e51d

update changelog

view details

David Sheldrick

commit sha 497926144b2fb553bc3491cd17ffcb1847597295

Simplify code and match iOS version more closely

view details

push time in 9 days

delete branch artsy/eigen

delete branch : profile-payment

delete time in 9 days

PR merged artsy/eigen

[MX-396] [MX-364] Create 'Payment' menu in profile tab

https://artsyproduct.atlassian.net/browse/MX-364

This PR is getting too big so I want to merge a few of these changes before doing follow up.

Changes in this PR

  • New Payments menu item in the profile tab.
  • New 'Add new card' screen. (This uses easy-peasy to manage the form state. I originally did it only as an experiment and was planning to convert to Formik but honestly with the computed properties and actions I prefer it to Formik so i left it as-is)
  • Create component for adding the new style generic page header PageWithSimpleHeader
  • Create new modal component FancyModal based on the core react-native Modal for doing the fancypants iOS 13 presentation style (should work on android too)
  • Create new Select component. This is part of palette but I haven't put it in the palette repo because I'm not convinced that doing that provides any value while we only have one react-native app. Happy for someone else to do that as follow-up if they think it's worthwhile.
  • Fixed a minor UI bug with the home hero
  • Applied the UI fixes from @samchieng's QA the other day
  • Fixed the Input component so that the KeyboardAvoidingView can keep the whole thing in view (+ padding!)

Planned Follow-up

  • [ ] Add an optional search field to the Select component
  • [ ] Tests!
  • [ ] Look into proving useful error messages to the user on the credit card form
  • [ ] Give the Select a ref prop so we can open the country select programatically after the user hits enter on the 'State, province, etc' field. Also make sure focus/tabbing works
  • [x] ~Look into updating tipsi-stripe in the hopes that they've made the credit card input behave more like a text input (we could use an onEnter callback, and it has weird focus/blur behaviour too)~
  • [ ] Placeholder for payment screen

FancyModal

Here it is being used on the collections page with a custom sheet height

new-collections-modal

Select

This also demonstrates FancyModal with the default sheet height (full screen)

new-select

Payment

image image

New Card

new-card-form

#skip_new_tests

+2750 -401

3 comments

35 changed files

ds300

pr closed time in 9 days

push eventRxSwiftCommunity/rxswiftcommunity.github.io

Ash Furrow (Via Travis)

commit sha 206d65990472b3dd13955b820d5d07ef644736dd

Site updated to 153754b

view details

push time in 9 days

issue commentartsy/eigen

[RFC] Pull Requests Template

@adamvert That makes sense! It's for sure a balance. Can you share any ideas on encouraging engineers to do that extra work in git, to still encourage improving things as you go, in the context of strict git/PR policies?

MounirDhahri

comment created time in 10 days

push eventRxSwiftCommunity/rxswiftcommunity.github.io

Ash Furrow (Via Travis)

commit sha cef8a8650890f29691ded7c81a973e2ef30b738b

Site updated to 153754b

view details

push time in 10 days

issue commentartsy/eigen

[RFC] Pull Requests Template

@adamvert Mmm! I can't dispute those logs 😍 But I worry about what might get lost. Specifically:

you end up thinking twice before you hide a bugfix inside a new feature

What's nice about having non-semantic and non-squashed commits is that it allows/encourages us to clean up the code as we go. I always put the fix in its own commit, because I do appreciate a precise log history – but I personally tolerate the messy logs because of the tradeoff of constantly-improving code seems worth it to me. Other teams/projects do have their own approaches, though – ideally we could trial out something like semantic commits on a smaller repo as a testbed 👍 (And automate this with Danger or Peril.)

MounirDhahri

comment created time in 11 days

delete branch artsy/peril-settings

delete branch : noon-standup

delete time in 11 days

push eventartsy/peril-settings

Anandaroop Roy

commit sha e748b042d57bbd28aab459e187c89e61740568d9

Update displayed time for big eng standup

view details

Ash Furrow

commit sha f4c8357de6a601bc204f234a0b08677911ce5daf

Merge pull request #158 from artsy/noon-standup Update the big standup time that's displayed in Slack

view details

push time in 11 days

PR merged artsy/peril-settings

Update the big standup time that's displayed in Slack

Just bumping this from 11:30 → 12:00 noon, to match reality 😄

+3 -3

0 comment

2 changed files

anandaroop

pr closed time in 11 days

push eventartsy/eigen

Mounir Dhahri

commit sha 035381828ec0146d4816455881a5898f7ffd6cab

update Personal Data Request Page

view details

Ashley Jelks

commit sha be3c7cf4bb2a54861a9c769943c1f27219587401

use above the fold flatlist on hubs rails

view details

David Sheldrick

commit sha fa34d2f9aa59f95096dfbd3809e5293a11cd6afb

Merge pull request #3509 from artsy/abovefold-coll-rail Use above the fold Flatlist on Collection Department Rails

view details

Brian Beckerle

commit sha 2d023c63a201970c15458c64e3042003685bd92c

Merge branch 'master' into adjust-personal-data-request-page

view details

artsy-peril[bot]

commit sha 9cccf8a8f8b0b426ae0067a3409f404a2f1a025b

update Personal Data Request Page (#3506) update Personal Data Request Page

view details

Ash Furrow

commit sha 374e3fa0328dc2b4e6b5bbcfabceb23341710cd5

Prepares for 6.4.9 development.

view details

artsy-peril[bot]

commit sha c07275a84760f35a9f71ac9bb745b857fa882ae4

Prepares for 6.4.9 development (#3510) Prepares for 6.4.9 development

view details

push time in 11 days

PR opened artsy/eigen

Prepares for 6.4.9 development Merge On Green

make next and changelog dance. Also prettier 😭

+59 -33

0 comment

3 changed files

pr created time in 11 days

create barnchartsy/eigen

branch : next-version

created branch time in 11 days

push eventRxSwiftCommunity/rxswiftcommunity.github.io

Ash Furrow (Via Travis)

commit sha a8aeb2c148f53da838782725087fee8ffc7e0020

Site updated to 153754b

view details

push time in 11 days

push eventashfurrow/blog

Ash Furrow

commit sha 1ad8c13430ee6c554d1e61a71103d558ef30d1bb

Moves Mobius talk to past.

view details

push time in 12 days

push eventRxSwiftCommunity/rxswiftcommunity.github.io

Ash Furrow (Via Travis)

commit sha d81449882292e4730a375fe3ec648935129a0d76

Site updated to 153754b

view details

push time in 12 days

push eventRxSwiftCommunity/rxswiftcommunity.github.io

Ash Furrow (Via Travis)

commit sha 4ccc94b74cec92659642ba7eb3abcfaf3008182c

Site updated to 153754b

view details

push time in 13 days

Pull request review commentartsy/eigen

[MX-364] Create 'Payment' menu in profile tab

+import { color, Sans } from "@artsy/palette"+import { fontFamily } from "@artsy/palette/dist/platform/fonts"+import { MyProfilePaymentNewCreditCardSaveCardMutation } from "__generated__/MyProfilePaymentNewCreditCardSaveCardMutation.graphql"+import { Action, action, computed, Computed, createComponentStore } from "easy-peasy"+import { Input } from "lib/Components/Input/Input"+import { Select } from "lib/Components/Select"+import { Stack } from "lib/Components/Stack"+import { defaultEnvironment } from "lib/relay/createEnvironment"+import { useInterval } from "lib/utils/useInterval"+import React, { useEffect, useRef, useState } from "react"+import { Alert } from "react-native"+import { commitMutation, graphql } from "react-relay"+// @ts-ignore+import stripe, { PaymentCardTextField } from "tipsi-stripe"+import { MyAccountFieldEditScreen } from "../MyAccount/Components/MyAccountFieldEditScreen"+import { __triggerRefresh } from "./MyProfilePayment"++interface CreditCardInputParams {+  cvc: string+  expMonth: number+  expYear: number+  number: string+}++interface FormField<Type = string> {+  value: Type | null+  touched: boolean+  required: boolean+  isPresent: Computed<this, boolean>+  setValue: Action<this, Type>+}+const emptyFieldState: () => FormField<any> = () => ({+  value: null,+  touched: false,+  required: true,+  isPresent: computed(self => {+    if (!self.required) {+      return true+    } else {+      return self.value !== null && (typeof self.value !== "string" || !!self.value)+    }+  }),+  setValue: action((state, payload) => {+    state.value = payload+  }),+})++interface FormFields {+  creditCard: FormField<{+    valid: boolean+    params: CreditCardInputParams+  }>+  fullName: FormField+  addressLine1: FormField+  addressLine2: FormField+  city: FormField+  postCode: FormField+  state: FormField+  country: FormField+}++interface Store {+  fields: FormFields+  allPresent: Computed<Store, boolean>+}++const useStore = createComponentStore<Store>({+  fields: {+    creditCard: emptyFieldState(),+    fullName: emptyFieldState(),+    addressLine1: emptyFieldState(),+    addressLine2: { ...emptyFieldState(), required: false },+    city: emptyFieldState(),+    postCode: emptyFieldState(),+    state: emptyFieldState(),+    country: emptyFieldState(),+  },+  allPresent: computed(store => {+    return Boolean(+      Object.keys(store.fields).every(k => store.fields[k as keyof FormFields].isPresent) &&+        store.fields.creditCard.value?.valid+    )+  }),+})++export const MyProfilePaymentNewCreditCard: React.FC<{}> = ({}) => {+  const [state, actions] = useStore()+  const [cardFieldIsFocused, setCardFieldIsFocused] = useState(false)+  const paymentInfoRef = useRef<any>(null)++  const addressLine1Ref = useRef<Input>(null)+  const addressLine2Ref = useRef<Input>(null)+  const cityRef = useRef<Input>(null)+  const postalCodeRef = useRef<Input>(null)+  const stateRef = useRef<Input>(null)++  // focus top field on mount+  useEffect(() => {+    paymentInfoRef.current?.focus()+  }, [])++  useInterval(() => {+    setCardFieldIsFocused(paymentInfoRef.current?.isFocused() ?? false)+  }, 100)++  const screenRef = useRef<MyAccountFieldEditScreen>(null)++  return (+    <MyAccountFieldEditScreen+      ref={screenRef}+      canSave={state.allPresent}+      title="Add new card"+      onSave={async () => {+        try {+          const stripeResult = await stripe.createTokenWithCard({+            ...state.fields.creditCard.value?.params,+            name: state.fields.fullName.value,+            addressLine1: state.fields.addressLine1.value,+            addressLine2: state.fields.addressLine2.value,+            addressCity: state.fields.city.value,+            addressState: state.fields.state.value,+            addressCountry: state.fields.country.value,+            addressZip: state.fields.postCode.value,+          })+          if (!stripeResult?.tokenId) {+            throw new Error(`Unexpected stripe card tokenization result ${JSON.stringify(stripeResult)}`)+          }+          const gravityResult = await saveCreditCard(stripeResult.tokenId)+          if (gravityResult.createCreditCard?.creditCardOrError?.creditCard) {+            await __triggerRefresh?.()+          } else {+            // TODO: we can probably present these errors to the user?+            throw new Error(+              `Error trying to save card ${JSON.stringify(+                gravityResult.createCreditCard?.creditCardOrError?.mutationError+              )}`+            )+          }+        } catch (e) {+          console.error(e)+          Alert.alert("Something went wrong while attempting to save your credit card. Please try again or contact us.")+        }+      }}+    >+      <Stack spacing={2}>+        <>+          <Sans size="3" mb={0.5}>+            Credit card+          </Sans>+          <PaymentCardTextField+            ref={paymentInfoRef}+            style={{+              fontFamily: fontFamily.sans.regular,+              height: 40,+              fontSize: 14,+              width: "100%",+              borderColor: cardFieldIsFocused+                ? state.fields.creditCard.value?.valid === false+                  ? color("red100")+                  : color("purple100")+                : color("black10"),+              borderWidth: 1,+              borderRadius: 0,+            }}+            onParamsChange={(valid: boolean, params: CreditCardInputParams) =>+              actions.fields.creditCard.setValue({+                valid,+                params,+              })+            }+            numberPlaceholder="Card number"+            expirationPlaceholder="MM/YY"+            cvcPlaceholde="CVC"+          />+        </>+        <Input+          title="Name on card"+          placeholder="Full name"+          onChangeText={actions.fields.fullName.setValue}+          returnKeyType="next"+          onSubmitEditing={() => addressLine1Ref.current?.focus()}+        />+        <Input+          ref={addressLine1Ref}+          title="Address line 1"+          placeholder="Add street address"+          onChangeText={actions.fields.addressLine1.setValue}+          returnKeyType="next"+          onSubmitEditing={() => addressLine2Ref.current?.focus()}+        />+        <Input+          ref={addressLine2Ref}+          title="Address line 2 (optional)"+          placeholder="Add apt, floor, suite, etc."+          onChangeText={actions.fields.addressLine2.setValue}+          returnKeyType="next"+          onSubmitEditing={() => cityRef.current?.focus()}+        />+        <Input+          ref={cityRef}+          title="City"+          placeholder="Add city"+          onChangeText={actions.fields.city.setValue}+          returnKeyType="next"+          onSubmitEditing={() => postalCodeRef.current?.focus()}+        />+        <Input+          ref={postalCodeRef}+          title="Postal Code"+          placeholder="Add postal code"+          onChangeText={actions.fields.postCode.setValue}+          returnKeyType="next"+          onSubmitEditing={() => stateRef.current?.focus()}+        />+        <Input+          ref={stateRef}+          title="State, province, or region"+          placeholder="Add State, Province, or Region"+          onChangeText={actions.fields.state.setValue}+          onSubmitEditing={() => {+            stateRef.current?.blur()+            screenRef.current?.scrollToEnd()+          }}+          returnKeyType="next"+        />+        <Select+          options={COUNTRY_SELECT_OPTIONS}+          placeholder="Select country"+          title="Country"+          onSelectValue={actions.fields.country.setValue}+          value={state.fields.country.value}+        ></Select>+      </Stack>+    </MyAccountFieldEditScreen>+  )+}++const saveCreditCard = (token: string) => {+  return new Promise<MyProfilePaymentNewCreditCardSaveCardMutation["response"]>((resolve, reject) => {+    commitMutation<MyProfilePaymentNewCreditCardSaveCardMutation>(defaultEnvironment, {+      mutation: graphql`+        mutation MyProfilePaymentNewCreditCardSaveCardMutation($input: CreditCardInput!) {+          createCreditCard(input: $input) {+            creditCardOrError {+              ... on CreditCardMutationSuccess {+                creditCard {+                  internalID+                }+              }+              ... on CreditCardMutationFailure {+                mutationError {+                  detail+                  error+                  message+                }+              }+            }+          }+        }+      `,+      onCompleted: resolve,+      onError: reject,+      variables: {+        input: {+          oneTimeUse: false,+          token,+        },+      },+    })+  })+}++const COUNTRY_SELECT_OPTIONS = [

I'm surprised that we don't already have this in the app. It looks like the existing form for Auctions bid flow uses a search-as-you-type API call to Google – huh! I like this quite a bit better.

ds300

comment created time in 14 days

Pull request review commentartsy/eigen

[MX-364] Create 'Payment' menu in profile tab

 export const FilterModalNavigator: React.SFC<FilterModalProps> = props => {     state.selectedFilters.length > 0 || (state.previouslyAppliedFilters.length === 0 && state.appliedFilters.length > 0)    return (-    <>-      {isFilterArtworksModalVisible && (-        <Modal isVisible={isFilterArtworksModalVisible} style={{ margin: 0 }}>-          <TouchableWithoutFeedback>-            <>-              <TouchableOpacity onPress={handleClosingModal} style={{ flexGrow: 1 }} />-              <ModalInnerView>-                <NavigatorIOS-                  navigationBarHidden={true}-                  initialRoute={{-                    component: FilterOptions,-                    passProps: { closeModal, id, slug },-                    title: "",-                  }}-                  style={{ flex: 1 }}-                />-                <ApplyButtonContainer>-                  <ApplyButton-                    disabled={!isApplyButtonEnabled}-                    onPress={() => {-                      const appliedFiltersParams = filterArtworksParams(state.appliedFilters)--                      tracking.trackEvent({-                        context_screen: Schema.ContextModules.Collection,-                        context_screen_owner_type: Schema.OwnerEntityTypes.Collection,-                        context_screen_owner_id: id,-                        context_screen_owner_slug: slug,-                        current: appliedFiltersParams,-                        changed: changedFiltersParams(appliedFiltersParams, state.selectedFilters),-                        action_type: Schema.ActionTypes.ChangeFilterParams,-                      })--                      applyFilters()-                    }}-                    block-                    width={100}-                    variant="primaryBlack"-                    size="large"-                  >-                    {getApplyButtonCount()}-                  </ApplyButton>-                </ApplyButtonContainer>-              </ModalInnerView>-            </>-          </TouchableWithoutFeedback>-        </Modal>-      )}-    </>+    <FancyModal visible={isFilterArtworksModalVisible} onBackgroundPressed={handleClosingModal} maxHeight={550}>

/cc @brainbicycle these are the only changes you'd need to merge in for #3507.

ds300

comment created time in 14 days

Pull request review commentartsy/eigen

[MX-364] Create 'Payment' menu in profile tab

+import { color, Sans } from "@artsy/palette"+import { fontFamily } from "@artsy/palette/dist/platform/fonts"+import { MyProfilePaymentNewCreditCardSaveCardMutation } from "__generated__/MyProfilePaymentNewCreditCardSaveCardMutation.graphql"+import { Action, action, computed, Computed, createComponentStore } from "easy-peasy"+import { Input } from "lib/Components/Input/Input"+import { Select } from "lib/Components/Select"+import { Stack } from "lib/Components/Stack"+import { defaultEnvironment } from "lib/relay/createEnvironment"+import { useInterval } from "lib/utils/useInterval"+import React, { useEffect, useRef, useState } from "react"+import { Alert } from "react-native"+import { commitMutation, graphql } from "react-relay"+// @ts-ignore+import stripe, { PaymentCardTextField } from "tipsi-stripe"+import { MyAccountFieldEditScreen } from "../MyAccount/Components/MyAccountFieldEditScreen"+import { __triggerRefresh } from "./MyProfilePayment"++interface CreditCardInputParams {+  cvc: string+  expMonth: number+  expYear: number+  number: string+}++interface FormField<Type = string> {+  value: Type | null+  touched: boolean+  required: boolean+  isPresent: Computed<this, boolean>+  setValue: Action<this, Type>+}+const emptyFieldState: () => FormField<any> = () => ({+  value: null,+  touched: false,+  required: true,+  isPresent: computed(self => {+    if (!self.required) {+      return true+    } else {+      return self.value !== null && (typeof self.value !== "string" || !!self.value)+    }+  }),+  setValue: action((state, payload) => {+    state.value = payload+  }),+})++interface FormFields {+  creditCard: FormField<{+    valid: boolean+    params: CreditCardInputParams+  }>+  fullName: FormField+  addressLine1: FormField+  addressLine2: FormField+  city: FormField+  postCode: FormField+  state: FormField+  country: FormField+}++interface Store {+  fields: FormFields+  allPresent: Computed<Store, boolean>+}++const useStore = createComponentStore<Store>({+  fields: {+    creditCard: emptyFieldState(),+    fullName: emptyFieldState(),+    addressLine1: emptyFieldState(),+    addressLine2: { ...emptyFieldState(), required: false },+    city: emptyFieldState(),+    postCode: emptyFieldState(),+    state: emptyFieldState(),+    country: emptyFieldState(),+  },+  allPresent: computed(store => {+    return Boolean(+      Object.keys(store.fields).every(k => store.fields[k as keyof FormFields].isPresent) &&+        store.fields.creditCard.value?.valid+    )+  }),+})++export const MyProfilePaymentNewCreditCard: React.FC<{}> = ({}) => {+  const [state, actions] = useStore()+  const [cardFieldIsFocused, setCardFieldIsFocused] = useState(false)+  const paymentInfoRef = useRef<any>(null)++  const addressLine1Ref = useRef<Input>(null)+  const addressLine2Ref = useRef<Input>(null)+  const cityRef = useRef<Input>(null)+  const postalCodeRef = useRef<Input>(null)+  const stateRef = useRef<Input>(null)++  // focus top field on mount+  useEffect(() => {+    paymentInfoRef.current?.focus()+  }, [])++  useInterval(() => {+    setCardFieldIsFocused(paymentInfoRef.current?.isFocused() ?? false)+  }, 100)++  const screenRef = useRef<MyAccountFieldEditScreen>(null)++  return (+    <MyAccountFieldEditScreen+      ref={screenRef}+      canSave={state.allPresent}+      title="Add new card"+      onSave={async () => {+        try {+          const stripeResult = await stripe.createTokenWithCard({+            ...state.fields.creditCard.value?.params,+            name: state.fields.fullName.value,+            addressLine1: state.fields.addressLine1.value,+            addressLine2: state.fields.addressLine2.value,+            addressCity: state.fields.city.value,+            addressState: state.fields.state.value,+            addressCountry: state.fields.country.value,+            addressZip: state.fields.postCode.value,+          })+          if (!stripeResult?.tokenId) {+            throw new Error(`Unexpected stripe card tokenization result ${JSON.stringify(stripeResult)}`)+          }+          const gravityResult = await saveCreditCard(stripeResult.tokenId)+          if (gravityResult.createCreditCard?.creditCardOrError?.creditCard) {+            await __triggerRefresh?.()+          } else {+            // TODO: we can probably present these errors to the user?+            throw new Error(+              `Error trying to save card ${JSON.stringify(+                gravityResult.createCreditCard?.creditCardOrError?.mutationError+              )}`+            )+          }+        } catch (e) {+          console.error(e)+          Alert.alert("Something went wrong while attempting to save your credit card. Please try again or contact us.")+        }+      }}+    >+      <Stack spacing={2}>+        <>+          <Sans size="3" mb={0.5}>+            Credit card+          </Sans>+          <PaymentCardTextField+            ref={paymentInfoRef}+            style={{+              fontFamily: fontFamily.sans.regular,+              height: 40,+              fontSize: 14,+              width: "100%",+              borderColor: cardFieldIsFocused+                ? state.fields.creditCard.value?.valid === false+                  ? color("red100")+                  : color("purple100")+                : color("black10"),+              borderWidth: 1,+              borderRadius: 0,+            }}+            onParamsChange={(valid: boolean, params: CreditCardInputParams) =>+              actions.fields.creditCard.setValue({+                valid,+                params,+              })+            }+            numberPlaceholder="Card number"+            expirationPlaceholder="MM/YY"+            cvcPlaceholde="CVC"+          />+        </>+        <Input+          title="Name on card"+          placeholder="Full name"+          onChangeText={actions.fields.fullName.setValue}+          returnKeyType="next"+          onSubmitEditing={() => addressLine1Ref.current?.focus()}+        />+        <Input+          ref={addressLine1Ref}+          title="Address line 1"+          placeholder="Add street address"+          onChangeText={actions.fields.addressLine1.setValue}+          returnKeyType="next"+          onSubmitEditing={() => addressLine2Ref.current?.focus()}+        />+        <Input+          ref={addressLine2Ref}+          title="Address line 2 (optional)"+          placeholder="Add apt, floor, suite, etc."+          onChangeText={actions.fields.addressLine2.setValue}+          returnKeyType="next"+          onSubmitEditing={() => cityRef.current?.focus()}+        />+        <Input+          ref={cityRef}+          title="City"+          placeholder="Add city"+          onChangeText={actions.fields.city.setValue}+          returnKeyType="next"+          onSubmitEditing={() => postalCodeRef.current?.focus()}+        />+        <Input+          ref={postalCodeRef}+          title="Postal Code"+          placeholder="Add postal code"+          onChangeText={actions.fields.postCode.setValue}+          returnKeyType="next"+          onSubmitEditing={() => stateRef.current?.focus()}+        />+        <Input+          ref={stateRef}+          title="State, province, or region"+          placeholder="Add State, Province, or Region"+          onChangeText={actions.fields.state.setValue}+          onSubmitEditing={() => {+            stateRef.current?.blur()+            screenRef.current?.scrollToEnd()+          }}+          returnKeyType="next"+        />+        <Select+          options={COUNTRY_SELECT_OPTIONS}+          placeholder="Select country"+          title="Country"+          onSelectValue={actions.fields.country.setValue}+          value={state.fields.country.value}+        ></Select>+      </Stack>+    </MyAccountFieldEditScreen>+  )+}++const saveCreditCard = (token: string) => {+  return new Promise<MyProfilePaymentNewCreditCardSaveCardMutation["response"]>((resolve, reject) => {+    commitMutation<MyProfilePaymentNewCreditCardSaveCardMutation>(defaultEnvironment, {+      mutation: graphql`+        mutation MyProfilePaymentNewCreditCardSaveCardMutation($input: CreditCardInput!) {+          createCreditCard(input: $input) {+            creditCardOrError {+              ... on CreditCardMutationSuccess {+                creditCard {+                  internalID+                }+              }+              ... on CreditCardMutationFailure {+                mutationError {+                  detail+                  error+                  message+                }+              }+            }+          }+        }+      `,+      onCompleted: resolve,+      onError: reject,+      variables: {+        input: {+          oneTimeUse: false,+          token,+        },+      },+    })+  })+}++const COUNTRY_SELECT_OPTIONS = [+  { label: "Afghanistan", value: "AF" },+  { label: "Åland Islands", value: "AX" },+  { label: "Albania", value: "AL" },+  { label: "Algeria", value: "DZ" },+  { label: "American Samoa", value: "AS" },+  { label: "Andorra", value: "AD" },+  { label: "Angola", value: "AO" },+  { label: "Anguilla", value: "AI" },+  { label: "Antarctica", value: "AQ" },+  { label: "Antigua and Barbuda", value: "AG" },+  { label: "Argentina", value: "AR" },+  { label: "Armenia", value: "AM" },+  { label: "Aruba", value: "AW" },+  { label: "Australia", value: "AU" },+  { label: "Austria", value: "AT" },+  { label: "Azerbaijan", value: "AZ" },+  { label: "Bahamas", value: "BS" },+  { label: "Bahrain", value: "BH" },+  { label: "Bangladesh", value: "BD" },+  { label: "Barbados", value: "BB" },+  { label: "Belarus", value: "BY" },+  { label: "Belgium", value: "BE" },+  { label: "Belize", value: "BZ" },+  { label: "Benin", value: "BJ" },+  { label: "Bermuda", value: "BM" },+  { label: "Bhutan", value: "BT" },+  { label: "Bolivia", value: "BO" },+  { label: "Bosnia and Herzegovina", value: "BA" },+  { label: "Botswana", value: "BW" },+  { label: "Bouvet Island", value: "BV" },+  { label: "Brazil", value: "BR" },+  { label: "British Indian Ocean Territory", value: "IO" },+  { label: "Brunei Darussalam", value: "BN" },+  { label: "Bulgaria", value: "BG" },+  { label: "Burkina Faso", value: "BF" },+  { label: "Burundi", value: "BI" },+  { label: "Cambodia", value: "KH" },+  { label: "Cameroon", value: "CM" },+  { label: "Canada", value: "CA" },+  { label: "Cape Verde", value: "CV" },+  { label: "Cayman Islands", value: "KY" },+  { label: "Central African Republic", value: "CF" },+  { label: "Chad", value: "TD" },+  { label: "Chile", value: "CL" },+  { label: "China", value: "CN" },+  { label: "Christmas Island", value: "CX" },+  { label: "Cocos (Keeling) Islands", value: "CC" },+  { label: "Colombia", value: "CO" },+  { label: "Comoros", value: "KM" },+  { label: "Congo", value: "CG" },+  { label: "Congo, The Democratic Republic of the", value: "CD" },+  { label: "Cook Islands", value: "CK" },+  { label: "Costa Rica", value: "CR" },+  { label: "Cote D'Ivoire", value: "CI" },+  { label: "Croatia", value: "HR" },+  { label: "Cuba", value: "CU" },+  { label: "Cyprus", value: "CY" },+  { label: "Czech Republic", value: "CZ" },+  { label: "Denmark", value: "DK" },+  { label: "Djibouti", value: "DJ" },+  { label: "Dominica", value: "DM" },+  { label: "Dominican Republic", value: "DO" },+  { label: "Ecuador", value: "EC" },+  { label: "Egypt", value: "EG" },+  { label: "El Salvador", value: "SV" },+  { label: "Equatorial Guinea", value: "GQ" },+  { label: "Eritrea", value: "ER" },+  { label: "Estonia", value: "EE" },+  { label: "Ethiopia", value: "ET" },+  { label: "Falkland Islands (Malvinas)", value: "FK" },+  { label: "Faroe Islands", value: "FO" },+  { label: "Fiji", value: "FJ" },+  { label: "Finland", value: "FI" },+  { label: "France", value: "FR" },+  { label: "French Guiana", value: "GF" },+  { label: "French Polynesia", value: "PF" },+  { label: "French Southern Territories", value: "TF" },+  { label: "Gabon", value: "GA" },+  { label: "Gambia", value: "GM" },+  { label: "Georgia", value: "GE" },+  { label: "Germany", value: "DE" },+  { label: "Ghana", value: "GH" },+  { label: "Gibraltar", value: "GI" },+  { label: "Greece", value: "GR" },+  { label: "Greenland", value: "GL" },+  { label: "Grenada", value: "GD" },+  { label: "Guadeloupe", value: "GP" },+  { label: "Guam", value: "GU" },+  { label: "Guatemala", value: "GT" },+  { label: "Guernsey", value: "GG" },+  { label: "Guinea", value: "GN" },+  { label: "Guinea-Bissau", value: "GW" },+  { label: "Guyana", value: "GY" },+  { label: "Haiti", value: "HT" },+  { label: "Heard Island and Mcdonald Islands", value: "HM" },+  { label: "Holy See (Vatican City State)", value: "VA" },

I guess the nice thing about the API call for country select is that it's future-compatible if they move the Holy See back to Avignon 🤣

ds300

comment created time in 14 days

more