Buying a car with Carvana

Standard

Recently our old car finally went down. Years ago the trade was worth $500 so I was happy to get $500 for it now. Though what a terrible time to buy a car with dealerships having low inventory.

We ended up going with Carvana because we could see what the actual price of the car, plus taxes, title, etc was going to cost us. Have you tried looking online at a dealership to see if they have a car you want? We were looking at some base models that had an MSRP in the range we were comfortable. When we browsed a few of the local dealerships they all had “MSRP: xx,xxx” but no actual price. When I reached out, with a link, even a VIN of a car I wanted they still couldn’t tell me the price they were selling it at. I had to drive there to see the actual car, as they may be reusing a listing with the same make, model, trim. With one dealer I did get them to tell me they were doing ‘market adjustments’ between $3,000 to $7,000 on top of the MSRP. The same dealer had a ‘dealer fee’ of $899 hidden in small text on their website.

The Buying Process

We had already been looking at EVs on Carvana to get an idea of those prices and alerts if one popped up so I already had an account. We didn’t end up getting an EV. Once my wife and I settled on a car, and played with the down payment to monthly slider we hit the buy now button. We started through the process which included filling out the typical name, address, drivers license stuff. It did have us move to their mobile application to make it easier taking pictures of my drivers license and uploading it. It was probably 20 minutes of my time spent. Like all dealerships they offered a handful of warranty options and even mentioned the current powertrain warranty and the one Carvana comes with. There wasn’t really any pushiness to pick one of the additional ones. We completed the electronic paperwork and went to bed.

The car we picked was to be delivered in 3 days time. So there were a few other tasks we had to complete. The first thing was Carvana wanted to verify we actually had the funds we were committing to the downpayment. They offer Plaid which can work with some banks to instantly verify, unfortunately it did not work for my bank. I called, got a Carvana person on the line pretty quick and we did a 3 way call with the bank. “Can you confirm that Jeff has at least $[downpayment] in the account ending in [last 4 digits of the account number]”. The bank said yes and that was it. The other task was to provide proof of insurance. The have some sort of affiliate insurance company they offer, but the prices were not competitive with my current insurance. I uploaded the proof of insurance and they were accepted.

Delivery Day

Next up was delivery day. The Carvana delivery driver showed up a few minutes early to our scheduled time. He unloaded the car, asked for my drivers license and proof of insurance. While he was completing paperwork on his end, I looked over the car and took it for a test drive. The car was great. Once I got back, we looked it over much closer, made sure we knew how to open the gas cover (is there a button? do you push it in and it pops out?, etc) and anything else. We agreed that we will take possession of the car. After that, I went inside and electronically signed the title paperwork.

7 Days

We had 7 days to return the car. Once the days were up, they filed the paperwork with the state we live in for the title and registration. Today the registration and license plate showed up and we are all good.

There are news stories in Florida, and other states about title and registration issues when buying a car with Carvana. I was a bit worried we would be one of those people, but it doesn’t look like thats the case. I was able to verify with the state the title and the names on the registration are good.

Improvements Carvana Could Make

There were only a couple of things I found confusing during the time we were buying the car.

  1. Once we got a quote from the insurance company they offer, and declined, a second ‘verify insurance’ task popped up. One was ‘Insurance verification’ and the other was ‘Insurance Verification’. Notice the capital ‘V’ on the second one. I uploaded the same document to both, so maybe it was just an edge case. See the screenshot below.
  2. On delivery day, hours before the delivery, I received the title documents to e-sign with instructions ‘sign these and we will tell you the next steps’. a. I am not going to sign the paperwork for a car before I accept it. b. Part of it was verifying under the penalty of perjury the mileage was accurate. Waiting to sign the document didn’t cause any issues, it was just confusing.
  3. When we were originally looking at EVs before seriously considering buying a car. I went through the pre-approval process that doesn’t hit your credit. Even after we bought the car, I still get their marketing emails for that pre-approval. Its like when you view a product on a big box website and ads for that product follow you around the internet after you went and bought it in store. Except here, I still purchased it online so they should know to stop emailing me.
Carvana 2 insurance verifications
2 Insurance Verifications

Finishing Up

Overall I am very happy we went with Carvana. The process was quite smooth. There weren’t any pushy sales people trying to close the deal, we knew how much we were paying for the car and the monthly payment before we even started the process to buy the car. The total time I spent dealing with the ‘buying process’ was probably a little over an hour. No sitting around waiting for the finance guy to finish up with the person before us.

Shopify App Bridge and React Router

Standard

I recently started building Shopify apps and ran into a problem with an embedded app and getting the URL change to reflect in the browser. The iframe would update, and I would be on the page, but the URL in the browser wouldn’t update. While not a critical feature, it’s sure annoying if you refresh the page and you can’t get the exact page on because instead of /orders/10 the URL only shows /orders/.

I spent hours researching how to do it, and found either out-of-date comments or things half done.

The not so obvious RoutePropagator is what you are looking for. After following the setup for the ClientRouter, the missing piece was adding in the RoutePropagator where I define my main <Switch> and <Route> statements.

//App.jsx
import { useRoutePropagation } from '@shopify/app-bridge-react';

function App({ location }) {
    //the magic was right here
    useRoutePropagation(location);

    return (
      <Switch>
          <Route path="/settings" component={Settings} />
          <Route path="/plan" exact component={Plan} />
          <Route path="/" exact component={Dashboard} />
      </Switch>
  );
});
//AppRouter.js
import {withRouter} from 'react-router'
import {useClientRouting} from '@shopify/app-bridge-react';
//Setup with the ClientRouter hook
function AppRouter(props) {
    const {history} = props;
    useClientRouting(history);
    return null;
}

export default withRouter(AppRouter);
//index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { BrowserRouter, Link } from 'react-router-dom'
import { Provider as AppBridgeProvider } from '@shopify/app-bridge-react'
import enTranslations from '@shopify/polaris/locales/en.json';
import {AppProvider as PolarisProvider} from "@shopify/polaris";
import config from './config';
import AppRouter from './AppRouter';
import { createStore, applyMiddleware } from 'redux';
import { Provider as ReduxProvider } from 'react-redux';
import '@shopify/polaris/dist/styles.css';

import rootReducer from './store/reducers/rootReducer';
const store = createStore(rootReducer, []);

const paramsSearcher = new URLSearchParams(window.location.search)
const findOrigin = paramsSearcher.get('shop') || 'test.myshopify.com';

window.sessionStorage.setItem('shopifyDomain', findOrigin);

const shopifyConfig = {
    apiKey: config.API_KEY,
    shopOrigin: findOrigin
}

const CustomLinkComponent = ({children, url, ...rest}) => {
    return (
        <Link to={url} {...rest}>{children}</Link>
    );
};

ReactDOM.render(
    <React.StrictMode>
        <BrowserRouter>
            <AppBridgeProvider config={shopifyConfig}>
                <ReduxProvider store={store}>
                    <PolarisProvider i18n={enTranslations} linkComponent={CustomLinkComponent}>
                        <AppRouter />
                        <App />
                    </PolarisProvider>
                </ReduxProvider>
        </AppBridgeProvider>
        </BrowserRouter>
    </React.StrictMode>,
    document.getElementById('root')
);

Shopify Polaris and the missing placeholder

Standard

I have recently been working on a Shopify app and came across a minor annoyance with a ResourceList that I solved, and then figured out why it was happening.

When adding a filter, it provides a search box, and all the examples had a placerholder in it, except mine did not have the placeholder.

While a minor thing I dug into the Shopify code and found I could pass in a queryPlaceholder property to set my own placeholder.

By setting the specific text it showed up just like I wanted. However in the component code you can see it will set a default placeholder if you don’t provide one.

When going back through the getting started directions, there is a spot to load english translations and that is what I was missing. It was an easy thing to miss but if you are missing a default placeholder, make sure you loaded the translations!

Interviewing after being the interviewer

Standard

I recently switched jobs after just shy of 5 years. Over those past 4+ years I have interviewed dozens of people for a job and learned a lot about the process.

The 2 way street

For starters, it helped me be relaxed during the interview process. I always tried to make sure it was a 2 way street. If a candidate doesn’t feel comfortable with me, it probably wouldn’t be a good fit. Therefore I liked to structure interviews as a conversation. The candidate would get to ask questions as they have them instead of just firing them off at the end. With my past experience, I was able to maintain that sort of things while I was being interviewed for a position.

Keeping with that idea, I had one interview where I knew it wasn’t going to be a good fit. We were already 2 or 3 in, so they bring in another member of the team to talk with and it just sort of died there. I am certainly grateful I was employed and didn’t have to take the first offer, otherwise if it came with this company, I imagine I wouldn’t be happy.

Sharing your test on Github…

You know who knows my Github username? My employer. If they see these random repositories popping up at night that are quite specific, it’s probably safe to assume they understand I am interviewing elsewhere. Now I don’t know if my employer at the time visited my Github to see what I was up to, but it definitely made me think of what I should name the repos.

What I believe is a better approach would be to keep them private and invite the interviewer or their team to review it. Github does have private repositories now.

$ Cha-Ching

The money aspect is always the weirdest. I told my wife on a few occasions that I didn’t know if I want to proceed with the ‘test’ because there was no salary range listed. If I spent 4+ hours on this test and what I need was outside what they were willing to pay it was a huge waste of time. In one instance, I knew I was talking to one of the guys at the top so I mentioned my concern before doing the test. If you are a negotiator, the downside here is you may have to throw out the number first.

While I didn’t make the job postings at my former job, it did instill in me just how frustrating it is for candidates not to know the salary range before hand.

My favorite question

If there is one thing you could change, what would it be?

Some people will give you really good answers. Sometimes it’s awkward if their boss is on the phone. My favorite time was when both the guy interviewing me answered and his boss separately answered. I really look for 2 different things when hearing the answers. I try to hear if it’s a genuine answer vs a b.s. answer and what it is. A fellow developer might be roadblocked by some process, whereas the CTO/COO wants to change a bigger picture thing.

This question also tends to lead the interviewers into rambling about their company culture. Often not trying to backpedal on their answer but just talking, and thinking about the different things they have experienced.

While I looked on and off for a while, Monday I start the new gig and I think it will be a great one. The personalities of the owners remind me of my last job where we got along quite well. While I am no longer working at a SaaS, the new company sells stuff that I needed. On Tuesday it arrives as I placed an order as a regular customer without my dev goggles on and I don’t think the fulfillment team knows who I am. It’s like Undercover Boss without the boss part.

Having a family and continuing education

Standard

Having a family definitely slows down the long nights going through an online course and digesting everything. Back in the bachelor life I could spend the entire weekend going through some course.

Now though, the kids are doing things, I am spending time with my wife, lawn care has to happen. All of this takes up time that in my single life would have been used for online learning. This means the courses take a lot longer to complete.

There is an upside to it that though. By doing a course spread of weeks instead of days, it re-enforces the concepts you learn. In this particular case, I am going through a Ruby on Rails course. By not being able to burn through it, it’s easier to retain the Ruby language and concepts of Rails.

It reminds me of when I learned to SCUBA dive. If you go on a nice Caribbean vacation, you can find places that will teach you to SCUBA dive in a weekend. If you take an 8 week course, you are much more comfortable putting the gear together as you have done it week after week. The weekend places, you do it 2 maybe 3 times, but come 6 months from now when you go diving again, that uncertainty of not remembering just how everything goes.

So in a few more weeks, when I am able to finish this course, I hope to be able to retain most of what I learned and start working on Ruby projects comfortably. The hard part of learning a new programming language is it’s so much faster to just use the language I am already proficient it.

Laravel Nova with your pipelines updated

Standard

Shortly after I added ‘Laravel Nova with your pipelines‘ I stumbled across a tweet on using an environment variable with composer. So instead of maintaining an auth.json file in the repository and using sed to replace placeholders, you can just add a COMPOSER_AUTH environment variable with the entire contents.

GitLab environment variables page

There had to be a better solution and here it was. Nice and simple.

Laravel Nova with your pipelines

Standard

If you use Laravel Nova, you undoubtedly were happy when Taylor started allowing us to use composer to install and update Nova. By doing so you create or edit your ~/.composer/auth.json file with something like the following:

{
    "http-basic": {
        "nova.laravel.com": {
            "username": "your-email@your-email.com",
            "password": "your-super-secret-token"
        }
    }
}

On your dev machine you need this file, along with your production or wherever you are building / deploying your site. Using forge, this is a simple git pull and not a complicated deployment.

I setup a GitLab pipeline so that when pushing the master branch, it will run my unit tests, then trigger forge to do the deployment.

To get composer to install and not error out means we had to add auth.json to our repository and in our build steps, copy it to the correct directory. By using variables, we don’t need to store our credentials in that file. Our auth.json is literally what we have above. We are going to replace your-email@your-email.com with our custom variable in the Gitlab CI/CD Environment Variables page.

GitLab CI variables

Here is what our test stage looks like. The ‘- sed’ lines replace our placeholders in auth.json with the variables we defined above.

phpunit:

  stage: test

  script:
    - cp auth.json ~/.composer/auth.json
    - sed -i "s/your-email@your-email.com/${NOVA_COMPOSER_EMAIL}/g" ~/.composer/auth.json
    - sed -i "s/your-super-secret-token/${NOVA_COMPOSER_TOKEN}/g" ~/.composer/auth.json
    - composer install --prefer-dist --no-ansi --no-interaction --no-progress --no-scripts
    - cp .env.testing .env
    - php artisan key:generate
    - phpunit --colors=never

There may be a more elegant way to achieve this, but this works and doesn’t jump through too many hoops.

Adding Facebook Pixel to Google Tag Manager

Standard

Adding the Facebook pixel to your Google Tag Manager account is really quite easy.

To start, let’s go to the Tags page and click the ‘New’ button. Where it is named ‘Untitled Tag’ go ahead and change that to ‘Facebook Pixel’. This is for informational purposes only.

Next, click ‘Choose a tag type to begin setup…’ and you are going to select ‘Custom HTML’. In the multi-line text box that opens, you will want to paste your Facebook pixel code there.

Down under ‘Tag firing options’, select’ Once per page’.

After that we are going to select our trigger. You are going to want to use the ‘All Pages Page View’ trigger that comes by default with your tag manager account. After that, you will want to click save.

Example facebook pixel configuration
Example Facebook Pixel setup

The last thing to do is submit your changes so they can be live.

To make sure you have it setup correctly, you can use the Facebook Pixel Helper that Facebook offers for free from the Chrome web store,

Chrome store link

Google Tag Manager ‘Page View’ tags not firing

Standard

If you landed on this page, you are probably trying to figure out why your ‘Page View’ tags aren’t firing. I ran across this problem myself, and that is why I am writing this blog post.

First up, make sure your Google Tag Manager is added to your site. This sounds dumb, but it is the first step we have to take. You should find code like below inside the <head> </head> tags of your website.

<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-MYGTMCODE');</script>
<!-- End Google Tag Manager -->

Now this is a basic setup. As long as that code is in there you should be good. Next, the question is, are you using the data layer? If you are, you of course added the following snippet of code like the examples show.

<script>
    dataLayer = [];
</script>

Now here is where the magic broke or happens. You may have skimmed over it, but that code needs to be ABOVE your Google Tag Manager code. I found that if it is below it, it will break the events and not fire correctly.

A correct implementation looks like the following. Make sure to update the tracking ID (this page example is: GTM-MYGTMCODE with your actual tracking ID.

<script>
    dataLayer = [];
</script>
<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-MYGTMCODE');</script>
<!-- End Google Tag Manager -->

I place this code as high in the <head></head> tags as I can. Hopefully this solved your problem of the Page View event not firing when it should have.