# Shopify Local Pick-up

## Headless Stores

### Prerequisites

While there are no FE prerequisites for the checkout, to be able to query stock levels on the FE, you need the following:

* Shopify Storefront API version 2023-04 or above
* Stores set up in Shopify that ***allow*** in-store pickup

### The Hook

To handle this, we’re best to create a `useFindInStore` hook — this would power a few parts:

* Fetching user location
* Fetching the product variant data
* Handling errors

#### The GraphQL Query

The `storeAvailability` connection is available on the variant, so before you can run the query, the user should have already selected a variant (*see 2 in need to knows*).

We can then present the user with the option to search for store stock. An example would be:

```
query FindInsStoreVariantsAndLocations($handle: String!, $latitude: Float!, $longitude: Float!) {
	product(handle: $handle) {
		variantBySelectedOptions(selectedOptions: $selectedOptions) {
			storeAvailability(first:250, near: { latitude: $latitude, longitude: $longitude }) {
				edges {
					node {
						available
                        pickUpTime
						location {
							name
							id
							address {
								formatted
								latitude
								longitude
							}
						}
					}
				}
			}
		}
	}
}
```

With the following variables:

```typescript
variables: {
  handle: product?.handle,
	selectedOptions: product?.activeVariant?.selectedOptions,
  latitude: coords.lat,
  longitude: coords.lng,
}
```

This will return this response:

```
{
    "data": {
        "product": {
            "variantBySelectedOptions": {
                "storeAvailability": {
                    "edges": [
                        {
                            "node": {
                                "available": true,
                                "pickUpTime": "Usually ready in 24 hours",
                                "location": {
                                    "name": "Doncaster Store",
                                    "id": "gid://shopify/Location/60903817288",
                                    "address": {
                                        "formatted": [
                                            "619 Doncaster Road",
                                            "Shop 1013",
                                            "Doncaster VIC 3108",
                                            "Australia"
                                        ],
                                        "latitude": -37.7851115,
                                        "longitude": 145.1262028
                                    }
                                }
                            }
                        },
                        {
                            "node": {
                                "available": true,
                                "pickUpTime": "Usually ready in 24 hours",
                                "location": {
                                    "name": "Armadale Store",
                                    "id": "gid://shopify/Location/60898607176",
                                    "address": {
                                        "formatted": [
                                            "1080 High Street",
                                            "Armadale VIC 3143",
                                            "Australia"
                                        ],
                                        "latitude": -37.855974,
                                        "longitude": 145.023201
                                    }
                                }
                            }
                        }
                    ]
                }
            }
        }
    }
}
```

From this response, you could flatten the array then sort by the distance:

```
const getDistance = useCallback((pos1: any, pos2: any) => {
  if (!pos1 || !pos2) {
    return 0
  }

  const R = 6371 // Radius of the earth in km
  const dLat = deg2rad(pos2.lat - pos1.lat) // deg2rad below
  const dLon = deg2rad(pos2.lng - pos1.lng)
  const a =
    Math.sin(dLat / 2) * Math.sin(dLat / 2) +
    Math.cos(deg2rad(pos1.lat)) * Math.cos(deg2rad(pos2.lat)) * Math.sin(dLon / 2) * Math.sin(dLon / 2)
  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
  return R * c
}, [])

const availability = edgeNormaliser(data?.product?.variantBySelectedOptions?.storeAvailability)
const sortedAvailability = availability?.map(location => ({...location, distance: getDistance(userCoords, {lat:location?.location?.latitude, lng:location?.location?.longitude})}))?.sort((a: any, b: any) => parseInt(a?.distance) - parseInt(b?.distance))

return storeAvailability
```

## Example Implementation

Whilst it is outdated, Tony Bianco is a good reference for how to implement native Shopify Pickup.

On the PDP, the drawer uses Google Maps API to search for the user's location with autocomplete, or the **Find My Location** uses navigator.geolocation to get the user's current position.

### Links

* PDP: <https://www.tonybianco.com/au/products/marcel-black-patent-10-5cm-heels>
* useFindStore Hook: <https://gitlab.com/dotdevv/clients/tonybianco/tony-bianco-website/-/blob/main/app/src/hooks/useFindStore.tsx> (not the best reference because it’s outdated, but an okay-ish reference for how it all pieces together)
* Find In Store Components: <https://gitlab.com/dotdevv/clients/tonybianco/tony-bianco-website/-/tree/main/app/src/components/FindInStore>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://developers.dotapparel.com.au/core/frontend/shopify-local-pick-up.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
