Stripe Apps縺九iStripe API螳溯。後心tripe Apps縺ァ豎コ貂医Ρ繝シ繧ッ繝輔Ο繝シ閾ェ蜍募喧3縲
蜑榊屓縺セ縺ァ縺ョ險倅コ九〒Stripe Apps縺ァ縺ョUI繝繧カ繧、繝ウ髢狗匱縺ォ縺、縺縺ヲ隗」隱ャ縺縺溘@縺セ縺励◆縲
莉雁屓縺ッStripe Apps縺九iStripe API繧貞ョ溯。後@縺ヲ莨壼藤諠蝣ア繧貞叙蠕励@縺ヲ縺縺阪∪縺吶
縺薙%縺セ縺ァ縺上k縺ィStripe Apps縺ァ螳溽樟縺ァ縺阪k繧「繝励Μ縺ョ蟷繧ょ、ァ縺阪¥蠎縺後k縺ィ諤昴>縺セ縺吶
縺薙ョ險倅コ九〒隱ャ譏弱☆繧九%縺ィ
- Stripe API縺ョ繧ウ繝シ繝繧」繝ウ繧ー
- 讀懆ィシ迺ー蠅縺ク縺ョ繧「繝繝励Ο繝シ繝画婿豕
縺。繧縺」縺ィ繧上°繧翫★繧峨>縺ァ縺吶′螳梧千ウサ縺ッ縺薙■繧峨〒縺吶ゅし繝ウ繝励Ν繧「繝励Μ縺ョMessaging繧偵き繧ケ繧ソ繝槭う繧コ縺励※縺翫j縺セ縺吶ョ縺ァ縲∽ク驛ィ髢「菫ゅョ縺ェ縺陦ィ遉コ繧よキキ縺倥▲縺ヲ縺翫j縺セ縺吶ョ縺ァ縺疲ウィ諢上¥縺縺輔>縲

Messaging繧オ繝ウ繝励Ν繧「繝励Μ縺ョ貅門y
莉雁屓縺ョ隗」隱ャ縺ッ繧オ繝ウ繝励Ν繧「繝励Μ縺ョMessaging繧貞茜逕ィ縺励※縺縺阪∪縺吶
螻暮幕縺吶k縺ィ荳玖ィ倥ョ繝繧」繝ャ繧ッ繝医Μ讒区舌↓縺ェ縺」縺ヲ縺縺セ縺吶

繧ォ繧ケ繧ソ繝槭う繧コ縺励※縺縺丞燕縺ォ荳驛ィ繧ス繝シ繧ケ菫ョ豁」縺悟ソ隕√〒縺吶
views縺ョ險ュ螳壼、画峩
繝繝輔か繝ォ繝医ョ險ュ螳壹〒縺ッ縲∬ェュ縺ソ霎シ縺ソview縺後ユ繧ケ繝育畑縺ョ縲窟pp.tsx縲阪↓縺ェ縺」縺ヲ縺縺セ縺吶ゅき繧ケ繧ソ繝槭う繧コ縺励※縺縺阪◆縺縺ョ縺ッ縲勲essaging.tsx縲阪〒縺吶ョ縺ァ險ュ螳壹ヵ繧。繧、繝ォ繧剃ソョ豁」縺励∪縺吶
蟇セ雎。縺ッ繝繧」繝ャ繧ッ繝医Μ逶エ荳九ョ縲茎tripe-app.json縲阪〒縺吶
"ui_extension": {
"views": [
{
"viewport": "stripe.dashboard.customer.detail",
"component": "App"
}
荳玖ィ倥↓螟画峩縺励∪縺吶
"ui_extension": {
"views": [
{
"viewport": "stripe.dashboard.customer.detail",
"component": "Messaging"
}
縺昴l縺ァ縺ッ螳滄圀縺ォ繧ォ繧ケ繧ソ繝槭う繧コ縺励※縺縺阪∪縺吶
create apps縺九i蟋九a繧九%縺ィ縺ッ蠢倥l縺ェ縺繧医≧縺ォ縲
遘√ョ迺ー蠅縺ァ縺ッ縲慧ayjs縲阪→縺縺繝励Λ繧ー繧、繝ウ繧ゅ↑縺九▲縺溘ョ縺ァ縲√%縺。繧峨b霑ス蜉縺ァ繧、繝ウ繧ケ繝医シ繝ォ縺励∪縺励◆縲
繧ィ繝ゥ繝シ縺瑚。ィ遉コ縺輔l繧句エ蜷医ッ蛟九縺ョ迺ー蠅縺斐→縺ォ霑ス蜉繝励Λ繧ー繧、繝ウ繧偵う繝ウ繧ケ繝医シ繝ォ縺励※縺縺阪∪縺吶
npm install dayjs --save
Messaging縺ョ繧ォ繧ケ繧ソ繝槭う繧コ
繧オ繝ウ繝励Ν繧「繝励Μ縺ョ繧ス繝シ繧ケ縺ッ螟ァ縺励◆縺薙→縺ッ縺励※縺翫i縺壹鬘ァ螳「ID縺ェ縺ゥ縺ッ蜿門セ励@縺ヲ縺縺セ縺吶′螳滄圀縺ォ陦ィ遉コ縺輔l縺ヲ縺繧九Γ繝繧サ繝シ繧ク縺ッFaker縺ァ莠句燕縺ォ險ュ螳壹@縺溘Γ繝繧サ繝シ繧ク繧定。ィ遉コ縺励※縺繧九ョ縺ソ縺ァ縺吶
<ContextView title="Recent Messages">
{fakeUserMessages.length ? (
<List
//fakeUserMessages縺九i繝。繝繧サ繝シ繧ク繧貞叙蠕
onAction={(id) => setOpenMessage(fakeUserMessages.find((message) => message.id === id))}
>
{fakeUserMessages.map((message) => (
//message繧貞コ蜉
<ListItem
id={message.id}
key={message.id}
title={
<>
<Box>{message.subject}</Box>
<Box css={{font: 'caption', color: 'secondary'}}>
{getEpochMsDisplayText(message.date)}
</Box>
</>
}
/>
))}
</List>
) : (
<Box>
No messages found.
</Box>
)}
繝。繝繧サ繝シ繧ク縺ョ荳ュ霄ォ縺ッ/src/fakeData.ts縺ォ螳夂セゥ縺輔l縺ヲ縺縺セ縺吶
繧ォ繧ケ繧ソ繝槭う繧コ蠕後ョ繧ス繝シ繧ケ縺ッ縺薙■繧峨〒縺吶
import {useEffect,useState} from 'react';
import {
Badge,
Box,
Button,
ContextView,
FocusView,
List,
ListItem,
} from '@stripe/ui-extension-sdk/ui';
import type {ExtensionContextValue} from '@stripe/ui-extension-sdk/context';
import type { Message } from "../types";
import {getEpochMsDisplayText} from '../utils/time';
import {fakeUserMessages} from '../fakeData';
import {useDashboardUserEmail} from '../utils/stripeApi';
/*霑ス蜉驛ィ蛻1 import*/
import Stripe from 'stripe';
import stripeClient from "../clients/stripe";
/*****/
const Messaging = ({environment, userContext}: ExtensionContextValue) => {
const dashboardUserEmail = useDashboardUserEmail();
const [openMessage, setOpenMessage] = useState<Message | undefined>(undefined);
/**霑ス蜉驛ィ蛻2縲鬘ァ螳「諠蝣ア縺ョ蜿門セ**/
//URL繝代Λ繝。繝シ繧ソ縺九iID繧貞叙蠕暦シ医%縺ョ蝣エ蜷医ッ鬘ァ螳「IDシ
const customerId = environment.objectContext?.id
//stripeAPI螳溯。
const [customer, setCustomer] = useState<Stripe.Customer | null>(null)
useEffect(() => {
if (!customerId) return;
stripeClient.customers.retrieve(customerId)
.then(response => {
if (response.deleted) return;
setCustomer(response)
})
}, [setCustomer, customerId])
return (
<ContextView title="Recent Messages">
{//霑ス蜉シ薙鬘ァ螳「諠蝣ア縺ョ陦ィ遉コ
customer ? (
<Box>{customer.name}</Box>
): (
<Box>鬘ァ螳「諠蝣ア縺後≠繧翫∪縺帙s</Box>
)}
{fakeUserMessages.length ? (
<List
onAction={(id) => setOpenMessage(fakeUserMessages.find((message) => message.id === id))}
>
{fakeUserMessages.map((message) => (
<ListItem
id={message.id}
key={message.id}
title={
<>
<Box>{message.subject}</Box>
<Box css={{font: 'caption', color: 'secondary'}}>
{getEpochMsDisplayText(message.date)}
</Box>
</>
}
/>
))}
</List>
) : (
<Box>
No messages found.
</Box>
)}
{!!customer &amp;amp;&amp;amp; 'email' in customer &amp;amp;&amp;amp; !!customer.email &amp;amp;&amp;amp; dashboardUserEmail &amp;amp;&amp;amp; (
<Box
css={{
font: 'caption',
color: 'secondary',
paddingY: 'medium',
}}
>
Displaying messages between {customer.email} and {dashboardUserEmail}.
</Box>
)}
<FocusView
shown={!!openMessage}
title={openMessage?.subject || '...'}
onClose={() => setOpenMessage(undefined)}
primaryAction={<Button onPress={() => setOpenMessage(undefined)}>Close</Button>}
>
<Box css={{paddingBottom: 'medium'}}>
<Badge type="info">{getEpochMsDisplayText(openMessage?.date || 0)}</Badge>
</Box>
{openMessage?.body}
</FocusView>
</ContextView>
);
};
export default Messaging;
繝ュ繝シ繧ォ繝ォ迺ー蠅縺ァ蜍輔°縺励※縺繧九≧縺。縺ッ縲√%縺ョ騾壹j鬘ァ螳「諠蝣ア縺ッ蜿門セ励〒縺阪∪縺帙s縲
API縺ァ莨壼藤諠蝣ア縺悟叙蠕励〒縺阪↑縺縺溘a縺ァ縺吶ュ縲ょョ滄圀縺ォAPI縺ョ謖吝虚繧堤「コ隱阪☆繧九◆繧√↓縺ッ縲ヾtripe縺ョ讀懆ィシ迺ー蠅縺ァ蜍輔°縺吝ソ隕√′縺ゅj縺セ縺吶

讀懆ィシ迺ー蠅縺ク縺ョ繧「繝繝励Ο繝シ繝
繧「繝励Μ縺ョ貅門y縺後〒縺阪◆繧唄tripe縺ョ讀懆ィシ迺ー蠅縺ク繧「繝繝励Ο繝シ繝峨@縺セ縺吶
stripe-app.json縺ョ譖エ譁ー
讀懆ィシ迺ー蠅縺ォ繧「繝繝励Ο繝シ繝峨☆繧九◆繧√↓縲ゅ∪縺壹茎tripe-app.json縲阪r邱ィ髮縺励∪縺
"id": "com.syun.messaging",
"version": "0.0.1",
"name": "Messaging",
"icon": "",
"permissions": [],
"app_backend": {
"webhooks": null
},
邱ィ髮縺吶k縺ョ縺ッ2轤ケ
- id縲Stripe Apps蜀縺ァ縺ョ荳諢上ョID縺ァ縺吶ゅし繝ウ繝励Ν繧「繝励Μ縺ョid縺ィ蜷後§縺縺ィ驥崎、繧ィ繝ゥ繝シ縺ォ縺ェ繧九ョ縺ァ縲∝、画峩縺悟ソ隕√〒縺吶
- version縲繧「繝繝励Ο繝シ繝峨ョ縺溘ウ縺ォ邱ィ髮縺吶k蠢隕√′縺ゅj縺セ縺吶ょ酔縺version縺ョ繧ゅョ縺後≠繧九→繧ィ繝ゥ繝シ縺ォ縺ェ繧翫∪縺吶
繧「繝励Μ縺ョ繧「繝繝励Ο繝シ繝
繧「繝繝励Ο繝シ繝峨☆繧九↓縺ッ繧「繝励Μ縺ョ繝繧」繝ャ繧ッ繝医Μ縺ァ荳玖ィ倥さ繝槭Φ繝峨r螳溯。後☆繧九□縺代
stripe apps upload
縺薙l縺ァStripe迺ー蠅縺ォ繧「繝繝励Ο繝シ繝峨〒縺阪∪縺励◆縲ら┌莠九↓蜍穂ス懊@縺ヲ縺繧九°遒コ隱阪@縺セ縺励g縺縲

繝繧ケ繝医Θ繝シ繧カ縺ョ豌丞錐シ医o縺九j縺・繧峨>縺ァ縺吶′豌丞錐繧貞叙蠕励@縺ヲ縺縺セ縺呻シ峨′API縺九i蜿門セ励〒縺阪※縺繧九%縺ィ縺檎「コ隱阪〒縺阪∪縺励◆縲
縺セ縺ィ繧
莉雁屓縺ッStripe API繧剃スソ縺」縺ヲ繝ェ繧「繝ォ繧ソ繧、繝縺ォ莨壼藤諠蝣ア繧貞叙蠕励@縺セ縺励◆縲
API縺ョ蜈ィ遞ョ縺ッ蜈ャ蠑上ョ繝峨く繝・繝。繝ウ繝縺ォ縺阪l縺縺ォ險倩シ峨&繧後※縺縺セ縺吶ョ縺ァ縺泌盾辣ァ縺上□縺輔>縲よアコ貂医Ρ繝シ繧ッ繝輔Ο繝シ縺ョ閾ェ蜍募喧縺セ縺ァ髟キ縺驕薙ョ繧翫〒縺励◆縺後∵ャ。蝗槭ッ繧縺」縺ィ閾ェ蜍募喧驛ィ蛻縺セ縺ァ讒狗ッ峨@縺ヲ縺縺阪∪縺吶


