Skip to content

Commit

Permalink
Add template
Browse files Browse the repository at this point in the history
  • Loading branch information
pepicrft committed Apr 11, 2023
0 parents commit e95df76
Show file tree
Hide file tree
Showing 20 changed files with 501 additions and 0 deletions.
7 changes: 7 additions & 0 deletions .gitignore
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
18 changes: 18 additions & 0 deletions .shopify/remix-patch.js
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))
})()
5 changes: 5 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"recommendations": [
"orsenkucher.vscode-graphql"
]
}
14 changes: 14 additions & 0 deletions README.md.liquid
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)
Binary file added app/assets/home-trophy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
47 changes: 47 additions & 0 deletions app/components/ProductsCard.jsx
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>
</>
);
}
14 changes: 14 additions & 0 deletions app/db.server.js
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
23 changes: 23 additions & 0 deletions app/models/token.server.js
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,
},
})
}
31 changes: 31 additions & 0 deletions app/root.jsx
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>
)
}
5 changes: 5 additions & 0 deletions app/routes/auth/$.jsx
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);
}
183 changes: 183 additions & 0 deletions app/routes/index.jsx
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',
]
6 changes: 6 additions & 0 deletions app/routes/webhooks.jsx
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});
}
26 changes: 26 additions & 0 deletions app/shopify/app.server.js
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}
Loading

0 comments on commit e95df76

Please sign in to comment.