はじめに
- https://www.s3lab.co.jp/blog/shopify/1820/ のつづき
- https://github.com/officialtpss/remix-shopify-admin-app-sample のコードを参考にした
開発
アプリ作成
% shopify app init
Welcome. Let’s get started by naming your app project. You can change it later.
? Your project name?
✔ s3lab-app-2
? Get started building your app:
✔ Start with Remix (recommended)
? For your Remix template, which language do you want?
✔ TypeScript
╭─ info ───────────────────────────────────────────────────────────────────────────────────────╮
│ │
│ Initializing project with `npm` │
│ Use the `--package-manager` flag to select a different package manager. │
│ │
╰──────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ success ────────────────────────────────────────────────────────────────────────────────────╮
│ │
│ s3lab-app-2 is ready for you to build! │
│ │
│ Next steps │
│ • Run `cd s3lab-app-2` │
│ • For extensions, run `shopify app generate extension` │
│ • To see your app, run `shopify app dev` │
│ │
│ Reference │
│ • Shopify docs [1] │
│ • For an overview of commands, run `shopify app --help` │
│ │
╰──────────────────────────────────────────────────────────────────────────────────────────────╯
[1] https://shopify.dev
% npm run dev
> dev
> shopify app dev
Before proceeding, your project needs to be associated with an app.
? Create this project as a new app on Shopify?
> (y) Yes, create it as a new app
(n) No, connect it to an existing app
Press ↑↓ arrows to select, enter or a shortcut to confirm.
(arm64) masayukimatsuo@s3l-mbp-202110-2 s3lab-app-2 % shopify app dev
Before proceeding, your project needs to be associated with an app.
? Create this project as a new app on Shopify?
✔ Yes, create it as a new app
? App name:
✔ s3lab-app-2
? Which store would you like to use to view your project?
✔ s3labteststore2
shopify.app.tomlにスコープを追加
[access_scopes]
scopes = "read_customers,read_orders,read_products,write_orders,write_products"
スコープをPartner管理画面のアプリに同期するためにデプロイ実行
shopify app deploy
注意: –resetをつけた場合、逆にPartner管理画面のスコープでshopify.app.tomlのスコープが上書きされる
Partner管理画面にスコープが同期されたことを確認
カスタムアプリとしてDistribute実行
- distributeしないとアプリ注文の表示ができず、以下のエラーが表示された
- Error: This app is not approved to access the Order object shopify
Shopifyアプリでの注文情報表示を確認
ソースコード
app/routes/app.orders.jsx
import {
IndexTable,
Page,
} from "@shopify/polaris";
import { authenticate } from "../shopify.server";
import { json } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
export const meta = () => {
return [{ title: "Orders" }];
};
export const loader = async ({ request }) => {
const { admin } = await authenticate.admin(request);
const response = await admin.graphql(
`query MyQuery {
orders(first: 50, reverse: true,) {
edges {
node {
id
createdAt
customer {
firstName
}
displayFulfillmentStatus
email
originalTotalPriceSet {
presentmentMoney {
amount
currencyCode
}
}
}
}
}
}`);
const responseJson = await response.json();
const orders = await responseJson?.data?.orders?.edges?.map(row => row?.node).map(
row => {
return {
...row,
...row?.customer,
...row?.originalTotalPriceSet?.presentmentMoney
}
}
);
return json({
orders
});
};
export default function Orders() {
const { orders } = useLoaderData();
const resourceName = {
singular: 'order',
plural: 'orders',
};
const rowMarkup = orders.map(
(
{ id, amount, createdAt, email, firstName },
index,
) => (
<IndexTable.Row
id={id}
key={id}
position={index}
>
<IndexTable.Cell>#{id?.replace('gid://shopify/Order/', '')}</IndexTable.Cell>
<IndexTable.Cell>{firstName}</IndexTable.Cell>
<IndexTable.Cell>{email}</IndexTable.Cell>
<IndexTable.Cell>{amount}</IndexTable.Cell>
<IndexTable.Cell>{createdAt}</IndexTable.Cell>
</IndexTable.Row>
),
);
return (
<Page title="Orders" fullWidth>
<IndexTable
resourceName={resourceName}
itemCount={orders.length}
headings={[
{ title: 'Order Id' },
{ title: 'Name' },
{ title: 'Email' },
{ title: 'Total' },
{ title: 'Created' },
]}
selectable={false}
>
{rowMarkup}
</IndexTable>
</Page>
);
}
app/data.ts
import { matchSorter } from "match-sorter";
import sortBy from "sort-by";
import invariant from "tiny-invariant";
type MeetingMutation = {
id?: string;
};
export type MeetingRecord = MeetingMutation & {
id: string;
createdAt: string;
};
const Meetings = {
records: {} as Record<string, MeetingRecord>,
async getAll(): Promise<MeetingRecord[]> {
return Object.keys(Meetings.records)
.map((key) => Meetings.records[key])
.sort(sortBy("-createdAt", "last"));
},
async get(id: string): Promise<MeetingRecord | null> {
return Meetings.records[id] || null;
},
async create(values: MeetingMutation): Promise<MeetingRecord> {
const id = values.id || Math.random().toString(36).substring(2, 9);
const createdAt = new Date().toISOString();
const newMeeting = { id, createdAt, ...values };
Meetings.records[id] = newMeeting;
return newMeeting;
},
async set(id: string, values: MeetingMutation): Promise<MeetingRecord> {
const meeting = await Meetings.get(id);
invariant(meeting, `No meeting found for ${id}`);
const updatedMeeting = { ...meeting, ...values };
Meetings.records[id] = updatedMeeting;
return updatedMeeting;
},
destroy(id: string): null {
delete Meetings.records[id];
return null;
},
};
export async function getMeetings(query?: string | null) {
let meetings = await Meetings.getAll();
if (query) {
meetings = matchSorter(meetings, query, {
keys: ["first", "last"],
});
}
return meetings.sort(sortBy("last", "createdAt"));
}
shopify.app.toml
・・・
[access_scopes]
scopes = "read_customers,read_orders,read_products,write_orders,write_products"
・・・
.env
SHOPIFY_API_KEY=
SHOPIFY_API_SECRET=