-
Notifications
You must be signed in to change notification settings - Fork 171
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit e95df76
Showing
20 changed files
with
501 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
node_modules | ||
|
||
/.cache | ||
/home/build | ||
/home/public/build | ||
.env | ||
home/sessions.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#!/usr/bin/env node | ||
const {promises: fs} = require('fs'); | ||
const {fileURLToPath} = require('url'); | ||
const {join: joinPath} = require('path'); | ||
|
||
(async () => { | ||
const packageJsonPath = joinPath(__dirname, '../node_modules/@shopify/cli/package.json') | ||
let packageJsonData = await fs.readFile(packageJsonPath) | ||
let packageJson = JSON.parse(packageJsonData) | ||
packageJson = { | ||
...packageJson, | ||
oclif: { | ||
...packageJson.oclif, | ||
plugins: [...packageJson.oclif.plugins, '@shopify/remix-app'], | ||
}, | ||
} | ||
await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2)) | ||
})() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"recommendations": [ | ||
"orsenkucher.vscode-graphql" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# {{ app_name }} | ||
|
||
This project contains a Shopify App powered by [Remix](https://remix.run/). | ||
|
||
## Set up | ||
|
||
1. Install dependencies: `{{ dependency_manager }} install`. | ||
2. Run `{{ dependency_manager }} dev`. | ||
|
||
## Resources | ||
|
||
- [Remix Docs](https://remix.run/docs/en/v1) | ||
- [App extensions](https://shopify.dev/docs/apps/app-extensions/list) | ||
- [Shopify Functions](https://shopify.dev/docs/api/functions) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { useState } from "react"; | ||
import { | ||
Card, | ||
Heading, | ||
TextContainer, | ||
DisplayText, | ||
TextStyle, | ||
} from "@shopify/polaris"; | ||
import { useSubmit } from "@remix-run/react"; | ||
|
||
export function ProductsCard({count}) { | ||
const submit = useSubmit(); | ||
|
||
function handleChange(event) { | ||
event.preventDefault() | ||
submit({ action: 'create-products'}, { replace: true, method: 'POST' }); | ||
} | ||
|
||
return ( | ||
<> | ||
<Card | ||
title="Product Counter" | ||
sectioned | ||
primaryFooterAction={{ | ||
content: "Populate 5 products", | ||
onAction: handleChange, | ||
// loading: isLoading, | ||
}} | ||
> | ||
<TextContainer spacing="loose"> | ||
<p> | ||
Sample products are created with a default title and price. You can | ||
remove them at any time. | ||
</p> | ||
<Heading element="h4"> | ||
TOTAL PRODUCTS | ||
<DisplayText size="medium"> | ||
<TextStyle variation="strong"> | ||
{count ? count : "-" } | ||
</TextStyle> | ||
</DisplayText> | ||
</Heading> | ||
</TextContainer> | ||
</Card> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import {PrismaClient} from '@prisma/client' | ||
|
||
let prisma | ||
|
||
if (process.env.NODE_ENV === 'production') { | ||
prisma = new PrismaClient() | ||
} else { | ||
if (!global.prisma) { | ||
global.prisma = new PrismaClient() | ||
} | ||
prisma = global.prisma | ||
} | ||
|
||
export default prisma |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import prisma from '../db.server.js' | ||
import {app} from '../shopify/app.server.js' | ||
|
||
export async function getToken(storeFQDN) { | ||
const storeToken = await prisma.tokens.findUnique({ | ||
where: { | ||
storeFQDN, | ||
}, | ||
}) | ||
return storeToken?.token | ||
} | ||
|
||
export async function setToken(storeFQDN, token) { | ||
return prisma.tokens.create({data: {storeFQDN, token, scopes: app.api.scopes}}) | ||
} | ||
|
||
export async function deleteToken(storeFQDN) { | ||
return prisma.tokens.delete({ | ||
where: { | ||
storeFQDN, | ||
}, | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import {Links, LiveReload, Meta, Outlet, Scripts, ScrollRestoration} from '@remix-run/react' | ||
import translations from '@shopify/polaris/locales/en.json' | ||
import {AppProvider as PolarisAppProvider} from '@shopify/polaris' | ||
import polarisStyles from '@shopify/polaris/build/esm/styles.css' | ||
|
||
export const meta = () => ({ | ||
charset: 'utf-8', | ||
title: 'New Remix App', | ||
viewport: 'width=device-width,initial-scale=1', | ||
}) | ||
|
||
export const links = () => [{rel: 'stylesheet', href: polarisStyles}] | ||
|
||
export default function App() { | ||
return ( | ||
<html lang="en"> | ||
<head> | ||
<Meta /> | ||
<Links /> | ||
</head> | ||
<body> | ||
<PolarisAppProvider i18n={translations}> | ||
<Outlet /> | ||
</PolarisAppProvider> | ||
<ScrollRestoration /> | ||
<Scripts /> | ||
<LiveReload /> | ||
</body> | ||
</html> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { authenticator } from '../../shopify/authenticator.server' | ||
|
||
export async function loader({request}) { | ||
return authenticator.authenticate('shopify-app', request); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
import {json} from '@remix-run/node' | ||
import {useLoaderData, useTransition} from '@remix-run/react' | ||
import {authenticator} from '../shopify/authenticator.server.js' | ||
import {Card, Page, Layout, TextContainer, Image, Stack, Link, Heading} from '@shopify/polaris' | ||
import {ProductsCard} from '../components/ProductsCard' | ||
import trophyImage from '../assets/home-trophy.png' | ||
import {useSubmit} from '@remix-run/react' | ||
|
||
export const loader = async ({request}) => { | ||
const {admin} = await authenticator.authenticate('shopify-app', request); | ||
const result = await admin.fetch('/products/count.json') | ||
return json(result) | ||
} | ||
|
||
export async function action({request}) { | ||
const {admin} = await authenticator.authenticate('shopify-app', request); | ||
await Promise.all( | ||
[...Array(5).keys()].map(async (i) => { | ||
await admin.mutate( | ||
`#graphql | ||
mutation populateProduct($input: ProductInput!) { | ||
productCreate(input: $input) { | ||
product { | ||
id | ||
} | ||
} | ||
} | ||
`, | ||
{ | ||
input: { | ||
title: `${randomTitle()}`, | ||
variants: [{price: randomPrice()}], | ||
}, | ||
}, | ||
) | ||
}), | ||
) | ||
const result = await admin.fetch('/products/count.json') | ||
return json(result) | ||
} | ||
|
||
export default function Index() { | ||
const data = useLoaderData() | ||
const transition = useTransition() | ||
const submit = useSubmit() | ||
|
||
function handlePopulateProducts(event) { | ||
event.preventDefault() | ||
submit({action: 'create-products'}, {replace: true, method: 'POST'}) | ||
} | ||
|
||
const populatingProducts = | ||
transition.state == 'submitting' && transition.submission.formData.get('action') == 'create-products' | ||
|
||
return ( | ||
<Page narrowWidth> | ||
<Layout> | ||
<Layout.Section> | ||
<Card sectioned> | ||
<Stack wrap={false} spacing="extraTight" distribution="trailing" alignment="center"> | ||
<Stack.Item fill> | ||
<TextContainer spacing="loose"> | ||
<Heading>Nice work on building a Shopify app 🎉</Heading> | ||
<p> | ||
Your app is ready to explore! It contains everything you need to get started including the{' '} | ||
<Link url="https://polaris.shopify.com/" external> | ||
Polaris design system | ||
</Link> | ||
,{' '} | ||
<Link url="https://shopify.dev/api/admin-graphql" external> | ||
Shopify Admin API | ||
</Link> | ||
, and{' '} | ||
<Link url="https://shopify.dev/apps/tools/app-bridge" external> | ||
App Bridge | ||
</Link>{' '} | ||
UI library and components. | ||
</p> | ||
<p> | ||
Ready to go? Start populating your app with some sample products to view and test in your store.{' '} | ||
</p> | ||
<p> | ||
Learn more about building out your app in{' '} | ||
<Link url="https://shopify.dev/apps/getting-started/add-functionality" external> | ||
this Shopify tutorial | ||
</Link>{' '} | ||
📚{' '} | ||
</p> | ||
</TextContainer> | ||
</Stack.Item> | ||
<Stack.Item> | ||
<div style={{padding: '0 20px'}}> | ||
<Image source={trophyImage} alt="Nice work on building a Shopify app" width={120} /> | ||
</div> | ||
</Stack.Item> | ||
</Stack> | ||
</Card> | ||
</Layout.Section> | ||
<Layout.Section> | ||
<ProductsCard count={data?.count} handlePopulate={handlePopulateProducts} populating={populatingProducts} /> | ||
</Layout.Section> | ||
</Layout> | ||
</Page> | ||
) | ||
} | ||
|
||
function randomTitle() { | ||
const adjective = ADJECTIVES[Math.floor(Math.random() * ADJECTIVES.length)] | ||
const noun = NOUNS[Math.floor(Math.random() * NOUNS.length)] | ||
return `${adjective} ${noun}` | ||
} | ||
|
||
function randomPrice() { | ||
return Math.round((Math.random() * 10 + Number.EPSILON) * 100) / 100 | ||
} | ||
|
||
const ADJECTIVES = [ | ||
'autumn', | ||
'hidden', | ||
'bitter', | ||
'misty', | ||
'silent', | ||
'empty', | ||
'dry', | ||
'dark', | ||
'summer', | ||
'icy', | ||
'delicate', | ||
'quiet', | ||
'white', | ||
'cool', | ||
'spring', | ||
'winter', | ||
'patient', | ||
'twilight', | ||
'dawn', | ||
'crimson', | ||
'wispy', | ||
'weathered', | ||
'blue', | ||
'billowing', | ||
'broken', | ||
'cold', | ||
'damp', | ||
'falling', | ||
'frosty', | ||
'green', | ||
'long', | ||
] | ||
|
||
const NOUNS = [ | ||
'waterfall', | ||
'river', | ||
'breeze', | ||
'moon', | ||
'rain', | ||
'wind', | ||
'sea', | ||
'morning', | ||
'snow', | ||
'lake', | ||
'sunset', | ||
'pine', | ||
'shadow', | ||
'leaf', | ||
'dawn', | ||
'glitter', | ||
'forest', | ||
'hill', | ||
'cloud', | ||
'meadow', | ||
'sun', | ||
'glade', | ||
'bird', | ||
'brook', | ||
'butterfly', | ||
'bush', | ||
'dew', | ||
'dust', | ||
'field', | ||
'fire', | ||
'flower', | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { authenticator } from '../shopify/authenticator.server' | ||
|
||
export const action = async ({request}) => { | ||
const { payload, topic } = await authenticator.authenticate('shopify-webhook', request); | ||
return new Response(null, { status: 200}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
const storeURL = process.env.SHOPIFY_STORE_URL | ||
const appURL = process.env.SHOPIFY_APP_URL | ||
|
||
const app = { | ||
name: process.env.SHOPIFY_APP_NAME, | ||
api: { | ||
key: process.env.SHOPIFY_APP_API_KEY, | ||
scopes: process.env.SHOPIFY_APP_SCOPES, | ||
secret: process.env.SHOPIFY_APP_API_SECRET, | ||
version: process.env.SHOPIFY_APP_API_VERSION, | ||
}, | ||
urls: { | ||
app: appURL, | ||
store: storeURL, | ||
webhooks: new URL(process.env.SHOPIFY_APP_WEBHOOK_PATH, appURL).toString(), | ||
auth: { | ||
authorization: new URL(process.env.SHOPIFY_APP_AUTH_AUTHORIZATION_PATH, storeURL).toString(), | ||
callback: new URL(process.env.SHOPIFY_APP_AUTH_CALLBACK_PATH, appURL).toString(), | ||
}, | ||
}, | ||
webhooks: { | ||
topics: process.env.SHOPIFY_APP_WEBHOOK_TOPICS.split(','), | ||
}, | ||
} | ||
|
||
export {app} |
Oops, something went wrong.