send message to new recipient

This commit is contained in:
m5r 2021-08-01 15:40:18 +08:00
parent 7d7c4cb495
commit 56e8880715
15 changed files with 456 additions and 39 deletions

View File

@ -1,16 +1,37 @@
import { BlitzApiRequest, BlitzApiResponse } from "blitz"; import { BlitzApiRequest, BlitzApiResponse } from "blitz";
import db from "db"; import db from "db";
import twilio from "twilio";
export default async function ddd(req: BlitzApiRequest, res: BlitzApiResponse) { export default async function ddd(req: BlitzApiRequest, res: BlitzApiResponse) {
await Promise.all([ /*await Promise.all([
db.message.deleteMany(), db.message.deleteMany(),
db.phoneCall.deleteMany(), db.phoneCall.deleteMany(),
db.phoneNumber.deleteMany(), db.phoneNumber.deleteMany(),
db.customer.deleteMany(), db.customer.deleteMany(),
]); ]);
await db.user.deleteMany(); await db.user.deleteMany();*/
const accountSid = "ACa886d066be0832990d1cf43fb1d53362";
const authToken = "8696a59a64b94bb4eba3548ed815953b";
/*const ddd = await twilio(accountSid, authToken)
.lookups
.v1
// .phoneNumbers("+33613370787")
.phoneNumbers("+33476982071")
.fetch();*/
try {
await twilio(accountSid, authToken).messages.create({
body: "content",
to: "+213744123789",
from: "+33757592025",
});
} catch (error) {
console.log(error.code);
console.log(error.moreInfo);
console.log(error.details);
// console.log(JSON.stringify(Object.keys(error)));
}
res.status(200).end(); res.status(200).send(ddd);
} }

View File

@ -16,7 +16,11 @@ const sendMessageQueue = Queue<Payload>(
const customer = await db.customer.findFirst({ where: { id: customerId } }); const customer = await db.customer.findFirst({ where: { id: customerId } });
const phoneNumber = await db.phoneNumber.findFirst({ where: { customerId } }); const phoneNumber = await db.phoneNumber.findFirst({ where: { customerId } });
const message = await twilio(customer!.accountSid!, customer!.authToken!).messages.create({ try {
const message = await twilio(
customer!.accountSid!,
customer!.authToken!
).messages.create({
body: content, body: content,
to, to,
from: phoneNumber!.phoneNumber, from: phoneNumber!.phoneNumber,
@ -25,6 +29,11 @@ const sendMessageQueue = Queue<Payload>(
where: { id }, where: { id },
data: { twilioSid: message.sid }, data: { twilioSid: message.sid },
}); });
} catch (error) {
// TODO: handle twilio error
console.log(error.code); // 21211
console.log(error.moreInfo); // https://www.twilio.com/docs/errors/21211
}
}, },
{ {
retry: ["1min"], retry: ["1min"],

View File

@ -8,7 +8,8 @@ import NewMessageArea from "./new-message-area";
export default function Conversation() { export default function Conversation() {
const router = useRouter(); const router = useRouter();
const conversation = useConversation(router.params.recipient)[0]; const recipient = decodeURIComponent(router.params.recipient);
const conversation = useConversation(recipient)[0];
const messagesListRef = useRef<HTMLUListElement>(null); const messagesListRef = useRef<HTMLUListElement>(null);
useEffect(() => { useEffect(() => {
@ -75,7 +76,7 @@ export default function Conversation() {
</ul> </ul>
</div> </div>
<Suspense fallback={null}> <Suspense fallback={null}>
<NewMessageArea /> <NewMessageArea recipient={recipient} />
</Suspense> </Suspense>
</> </>
); );

View File

@ -8,14 +8,18 @@ import { Direction, Message, MessageStatus } from "../../../db";
import getConversationsQuery from "../queries/get-conversations"; import getConversationsQuery from "../queries/get-conversations";
import useCurrentCustomer from "../../core/hooks/use-current-customer"; import useCurrentCustomer from "../../core/hooks/use-current-customer";
import useCustomerPhoneNumber from "../../core/hooks/use-customer-phone-number"; import useCustomerPhoneNumber from "../../core/hooks/use-customer-phone-number";
import { FunctionComponent } from "react";
type Form = { type Form = {
content: string; content: string;
}; };
export default function NewMessageArea() { type Props = {
const router = useRouter(); recipient: string;
const recipient = router.params.recipient; onSend?: () => void;
};
const NewMessageArea: FunctionComponent<Props> = ({ recipient, onSend }) => {
const { customer } = useCurrentCustomer(); const { customer } = useCurrentCustomer();
const phoneNumber = useCustomerPhoneNumber(); const phoneNumber = useCustomerPhoneNumber();
const sendMessageMutation = useMutation(sendMessage)[0]; const sendMessageMutation = useMutation(sendMessage)[0];
@ -30,6 +34,10 @@ export default function NewMessageArea() {
formState: { isSubmitting }, formState: { isSubmitting },
} = useForm<Form>(); } = useForm<Form>();
const onSubmit = handleSubmit(async ({ content }) => { const onSubmit = handleSubmit(async ({ content }) => {
if (!recipient) {
return;
}
if (isSubmitting) { if (isSubmitting) {
return; return;
} }
@ -60,6 +68,7 @@ export default function NewMessageArea() {
{ refetch: false } { refetch: false }
); );
setValue("content", ""); setValue("content", "");
onSend?.();
await sendMessageMutation({ to: recipient, content }); await sendMessageMutation({ to: recipient, content });
await refetchConversations({ cancelRefetch: true }); await refetchConversations({ cancelRefetch: true });
}); });
@ -83,7 +92,9 @@ export default function NewMessageArea() {
</button> </button>
</form> </form>
); );
} };
export default NewMessageArea;
function uuidv4() { function uuidv4() {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) { return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {

View File

@ -0,0 +1,53 @@
import { Suspense, useState } from "react";
import { BottomSheet } from "react-spring-bottom-sheet";
import { atom, useAtom } from "jotai";
import { useRouter, Routes } from "blitz";
import "react-spring-bottom-sheet/dist/style.css";
import NewMessageArea from "./new-message-area";
export const bottomSheetOpenAtom = atom(false);
export default function NewMessageBottomSheet() {
const router = useRouter();
const [isOpen, setIsOpen] = useAtom(bottomSheetOpenAtom);
const [recipient, setRecipient] = useState("");
return (
<BottomSheet
open={isOpen}
onDismiss={() => setIsOpen(false)}
snapPoints={({ maxHeight }) => maxHeight / 2}
header={
<div className="w-full flex items-center justify-center p-4 text-black relative">
<span className="font-semibold text-base">New Message</span>
<button onClick={() => setIsOpen(false)} className="absolute right-4">
Cancel
</button>
</div>
}
>
<main className="flex flex-col h-full overflow-hidden">
<div className="flex items-center p-4 border-t border-b">
<span className="mr-4 text-[#333]">To:</span>
<input
onChange={(event) => setRecipient(event.target.value)}
className="bg-none border-none outline-none flex-1 text-black"
/>
</div>
<Suspense fallback={null}>
<NewMessageArea
recipient={recipient}
onSend={() => {
router
.push(Routes.ConversationPage({ recipient }))
.then(() => setIsOpen(false));
}}
/>
</Suspense>
</main>
</BottomSheet>
);
}

View File

@ -0,0 +1,21 @@
import type { FunctionComponent, MouseEventHandler } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faEdit } from "@fortawesome/pro-regular-svg-icons";
type Props = {
onClick: MouseEventHandler<HTMLButtonElement>;
};
const NewMessageButton: FunctionComponent<Props> = ({ onClick }) => {
return (
<button
onClick={onClick}
className="absolute bottom-20 right-6
w-14 h-14 bg-gray-800 rounded-full hover:bg-gray-900 active:shadow-lg shadow transition ease-in duration-200 focus:outline-none"
>
<FontAwesomeIcon size="lg" className="m-auto pl-1.5 text-white w-8 h-8" icon={faEdit} />
</button>
);
};
export default NewMessageButton;

View File

@ -14,6 +14,7 @@ export default function useConversation(recipient: string) {
return conversations[recipient]!; return conversations[recipient]!;
}, },
keepPreviousData: true,
} }
); );
} }

View File

@ -0,0 +1,14 @@
import { useQuery } from "blitz";
import getConversationsQuery from "../queries/get-conversations";
export default function useKnownRecipients() {
return useQuery(
getConversationsQuery,
{},
{
select(conversations) {
return Object.keys(conversations);
},
}
);
}

View File

@ -1,11 +1,15 @@
import { resolver } from "blitz"; import { resolver } from "blitz";
import { z } from "zod"; import { z } from "zod";
import twilio from "twilio";
import db, { Direction, MessageStatus } from "../../../db"; import db, { Direction, MessageStatus } from "../../../db";
import getCurrentCustomer from "../../customers/queries/get-current-customer"; import getCurrentCustomer from "../../customers/queries/get-current-customer";
import getCustomerPhoneNumber from "../../phone-numbers/queries/get-customer-phone-number"; import getCustomerPhoneNumber from "../../phone-numbers/queries/get-customer-phone-number";
import { encrypt } from "../../../db/_encryption"; import { encrypt } from "../../../db/_encryption";
import sendMessageQueue from "../../api/queue/send-message"; import sendMessageQueue from "../../api/queue/send-message";
import appLogger from "../../../integrations/logger";
const logger = appLogger.child({ mutation: "send-message" });
const Body = z.object({ const Body = z.object({
content: z.string(), content: z.string(),
@ -17,6 +21,15 @@ export default resolver.pipe(
resolver.authorize(), resolver.authorize(),
async ({ content, to }, context) => { async ({ content, to }, context) => {
const customer = await getCurrentCustomer(null, context); const customer = await getCurrentCustomer(null, context);
try {
await twilio(customer!.accountSid!, customer!.authToken!)
.lookups.v1.phoneNumbers(to)
.fetch();
} catch (error) {
logger.error(error);
return;
}
const customerId = customer!.id; const customerId = customer!.id;
const customerPhoneNumber = await getCustomerPhoneNumber({ customerId }, context); const customerPhoneNumber = await getCustomerPhoneNumber({ customerId }, context);

View File

@ -1,22 +1,28 @@
import { Suspense } from "react"; import { Suspense, useState } from "react";
import type { BlitzPage } from "blitz"; import type { BlitzPage } from "blitz";
import { Routes } from "blitz"; import { Routes } from "blitz";
import { useAtom } from "jotai";
import Layout from "../../core/layouts/layout"; import Layout from "../../core/layouts/layout";
import ConversationsList from "../components/conversations-list"; import ConversationsList from "../components/conversations-list";
import NewMessageButton from "../components/new-message-button";
import NewMessageBottomSheet, { bottomSheetOpenAtom } from "../components/new-message-bottom-sheet";
import useRequireOnboarding from "../../core/hooks/use-require-onboarding"; import useRequireOnboarding from "../../core/hooks/use-require-onboarding";
const Messages: BlitzPage = () => { const Messages: BlitzPage = () => {
useRequireOnboarding(); useRequireOnboarding();
const setIsOpen = useAtom(bottomSheetOpenAtom)[1];
return ( return (
<> <>
<div className="flex flex-col space-y-6 p-6"> <div className="flex flex-col space-y-6 p-6">
<p>Messages page</p> <h2 className="text-3xl font-bold">Messages</h2>
</div> </div>
<Suspense fallback="Loading..."> <Suspense fallback="Loading...">
<ConversationsList /> <ConversationsList />
</Suspense> </Suspense>
<NewMessageButton onClick={() => setIsOpen(true)} />
<NewMessageBottomSheet />
</> </>
); );
}; };

View File

@ -16,7 +16,7 @@ const ConversationPage: BlitzPage = () => {
useRequireOnboarding(); useRequireOnboarding();
const router = useRouter(); const router = useRouter();
const recipient = router.params.recipient; const recipient = decodeURIComponent(router.params.recipient);
return ( return (
<> <>
@ -39,7 +39,7 @@ const ConversationPage: BlitzPage = () => {
ConversationPage.getLayout = function ConversationLayout(page) { ConversationPage.getLayout = function ConversationLayout(page) {
const router = useRouter(); const router = useRouter();
const recipient = router.params.recipient; const recipient = decodeURIComponent(router.params.recipient);
const pageTitle = `Messages with ${recipient}`; const pageTitle = `Messages with ${recipient}`;
return ( return (

View File

@ -12,7 +12,7 @@ const PhoneCalls: BlitzPage = () => {
return ( return (
<> <>
<div className="flex flex-col space-y-6 p-6"> <div className="flex flex-col space-y-6 p-6">
<p>Calls page</p> <h2 className="text-3xl font-bold">Calls</h2>
</div> </div>
<Suspense fallback="Loading..."> <Suspense fallback="Loading...">
<PhoneCallsList /> <PhoneCallsList />

View File

@ -33,6 +33,10 @@ const Settings: BlitzPage = () => {
useRequireOnboarding(); useRequireOnboarding();
return ( return (
<>
<div className="flex flex-col space-y-6 p-6">
<h2 className="text-3xl font-bold">Settings</h2>
</div>
<div className="flex flex-col space-y-6 p-6"> <div className="flex flex-col space-y-6 p-6">
<aside className="py-6 lg:col-span-3"> <aside className="py-6 lg:col-span-3">
<nav className="space-y-1"> <nav className="space-y-1">
@ -49,6 +53,7 @@ const Settings: BlitzPage = () => {
</nav> </nav>
</aside> </aside>
</div> </div>
</>
); );
}; };

259
package-lock.json generated
View File

@ -1329,6 +1329,11 @@
"chalk": "^4.0.0" "chalk": "^4.0.0"
} }
}, },
"@juggle/resize-observer": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.3.1.tgz",
"integrity": "sha512-zMM9Ds+SawiUkakS7y94Ymqx+S0ORzpG3frZirN3l+UlXUmSUR7hF4wxCVqW+ei94JzV5kt0uXBcoOEAuiydrw=="
},
"@mrleebo/prisma-ast": { "@mrleebo/prisma-ast": {
"version": "0.2.5", "version": "0.2.5",
"resolved": "https://registry.npmjs.org/@mrleebo/prisma-ast/-/prisma-ast-0.2.5.tgz", "resolved": "https://registry.npmjs.org/@mrleebo/prisma-ast/-/prisma-ast-0.2.5.tgz",
@ -2212,6 +2217,161 @@
"pino": "^6.11.3" "pino": "^6.11.3"
} }
}, },
"@reach/portal": {
"version": "0.13.2",
"resolved": "https://registry.npmjs.org/@reach/portal/-/portal-0.13.2.tgz",
"integrity": "sha512-g74BnCdtuTGthzzHn2cWW+bcyIYb0iIE/yRsm89i8oNzNgpopbkh9UY8TPbhNlys52h7U60s4kpRTmcq+JqsTA==",
"requires": {
"@reach/utils": "0.13.2",
"tslib": "^2.1.0"
}
},
"@reach/utils": {
"version": "0.13.2",
"resolved": "https://registry.npmjs.org/@reach/utils/-/utils-0.13.2.tgz",
"integrity": "sha512-3ir6cN60zvUrwjOJu7C6jec/samqAeyAB12ZADK+qjnmQPdzSYldrFWwDVV5H0WkhbYXR3uh+eImu13hCetNPQ==",
"requires": {
"@types/warning": "^3.0.0",
"tslib": "^2.1.0",
"warning": "^4.0.3"
}
},
"@react-aria/interactions": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.5.0.tgz",
"integrity": "sha512-EL5GWpzM9UHU17LztwgL/tF3H2tLG375CD64kieCgSfsRcCSlC3pavnPy9jbS8levdBQ2qo9e2xfoX5VtfJisw==",
"requires": {
"@babel/runtime": "^7.6.2",
"@react-aria/utils": "^3.8.1",
"@react-types/shared": "^3.7.0"
}
},
"@react-aria/ssr": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.0.2.tgz",
"integrity": "sha512-+M0wrUlc2eTuMiwTfd0iFZJGu2hvMeYBLE8gRdbPJCDjLhrNWOQLKR/y6ntxQ9u8zjrNl/YPOdRtcqkA2EBnAQ==",
"requires": {
"@babel/runtime": "^7.6.2"
}
},
"@react-aria/utils": {
"version": "3.8.1",
"resolved": "https://registry.npmjs.org/@react-aria/utils/-/utils-3.8.1.tgz",
"integrity": "sha512-SvFf1T2HHAId6LS4+gbJNLQU9wr5GHuR5wA+HOtfVkZ82v3xhOnzfjR5qgjSLYGsPfqNgci5cpKYlHf4YqMf5w==",
"requires": {
"@babel/runtime": "^7.6.2",
"@react-aria/ssr": "^3.0.2",
"@react-stately/utils": "^3.2.1",
"@react-types/shared": "^3.7.0",
"clsx": "^1.1.1"
}
},
"@react-spring/animated": {
"version": "9.2.4",
"resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.2.4.tgz",
"integrity": "sha512-AfV6ZM8pCCAT29GY5C8/1bOPjZrv/7kD0vedjiE/tEYvNDwg9GlscrvsTViWR2XykJoYrDfdkYArrldWpsCJ5g==",
"requires": {
"@react-spring/shared": "~9.2.0",
"@react-spring/types": "~9.2.0"
}
},
"@react-spring/core": {
"version": "9.2.4",
"resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.2.4.tgz",
"integrity": "sha512-R+PwyfsjiuYCWqaTTfCpYpRmsP0h87RNm7uxC1Uxy7QAHUfHEm2sAHn+AdHPwq/MbVwDssVT8C5yf2WGcqiXGg==",
"requires": {
"@react-spring/animated": "~9.2.0",
"@react-spring/shared": "~9.2.0",
"@react-spring/types": "~9.2.0"
}
},
"@react-spring/konva": {
"version": "9.2.4",
"resolved": "https://registry.npmjs.org/@react-spring/konva/-/konva-9.2.4.tgz",
"integrity": "sha512-19anDOIkfjcydDTfGgVIuZ3lruZxKubYGs9oHCswaP8SRLj7c1kkopJHUr/S4LXGxiIdqdF0XucWm0iTEPEq4w==",
"requires": {
"@react-spring/animated": "~9.2.0",
"@react-spring/core": "~9.2.0",
"@react-spring/shared": "~9.2.0",
"@react-spring/types": "~9.2.0"
}
},
"@react-spring/native": {
"version": "9.2.4",
"resolved": "https://registry.npmjs.org/@react-spring/native/-/native-9.2.4.tgz",
"integrity": "sha512-xKJWKh5qOhSclpL3iuGwJRLoZzTNvlBEnIrMs8yh8xvX6z9Lmnu4uGu5DpfrnM1GzBvRoktoCoLEx/VcEYFSng==",
"requires": {
"@react-spring/animated": "~9.2.0",
"@react-spring/core": "~9.2.0",
"@react-spring/shared": "~9.2.0",
"@react-spring/types": "~9.2.0"
}
},
"@react-spring/rafz": {
"version": "9.2.4",
"resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.2.4.tgz",
"integrity": "sha512-SOKf9eue+vAX+DGo7kWYNl9i9J3gPUlQjifIcV9Bzw9h3i30wPOOP0TjS7iMG/kLp2cdHQYDNFte6nt23VAZkQ=="
},
"@react-spring/shared": {
"version": "9.2.4",
"resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.2.4.tgz",
"integrity": "sha512-ZEr4l2BxmyFRUvRA2VCkPfCJii4E7cGkwbjmTBx1EmcGrOnde/V2eF5dxqCTY3k35QuCegkrWe0coRJVkh8q2Q==",
"requires": {
"@react-spring/rafz": "~9.2.0",
"@react-spring/types": "~9.2.0"
}
},
"@react-spring/three": {
"version": "9.2.4",
"resolved": "https://registry.npmjs.org/@react-spring/three/-/three-9.2.4.tgz",
"integrity": "sha512-ljFig7XW099VWwRPKPUf+4yYLivp/sSWXN3oO5SJOF/9BSoV1quS/9chZ5Myl5J14od3CsHf89Tv4FdlX5kHlA==",
"requires": {
"@react-spring/animated": "~9.2.0",
"@react-spring/core": "~9.2.0",
"@react-spring/shared": "~9.2.0",
"@react-spring/types": "~9.2.0"
}
},
"@react-spring/types": {
"version": "9.2.4",
"resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.2.4.tgz",
"integrity": "sha512-zHUXrWO8nweUN/ISjrjqU7GgXXvoEbFca1CgiE0TY0H/dqJb3l+Rhx8ecPVNYimzFg3ZZ1/T0egpLop8SOv4aA=="
},
"@react-spring/web": {
"version": "9.2.4",
"resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.2.4.tgz",
"integrity": "sha512-vtPvOalLFvuju/MDBtoSnCyt0xXSL6Amyv82fljOuWPl1yGd4M1WteijnYL9Zlriljl0a3oXcPunAVYTD9dbDQ==",
"requires": {
"@react-spring/animated": "~9.2.0",
"@react-spring/core": "~9.2.0",
"@react-spring/shared": "~9.2.0",
"@react-spring/types": "~9.2.0"
}
},
"@react-spring/zdog": {
"version": "9.2.4",
"resolved": "https://registry.npmjs.org/@react-spring/zdog/-/zdog-9.2.4.tgz",
"integrity": "sha512-rv7ptedS37SHr6yuCbRkUErAzAhebdgt8f4KUtZWzseC+7qLNkaZWf+uujgsb881qAuX9b9yz8rre9UKeYepgw==",
"requires": {
"@react-spring/animated": "~9.2.0",
"@react-spring/core": "~9.2.0",
"@react-spring/shared": "~9.2.0",
"@react-spring/types": "~9.2.0"
}
},
"@react-stately/utils": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@react-stately/utils/-/utils-3.2.1.tgz",
"integrity": "sha512-H79CYKPiQZrO1/dMSwjRJxsRlYg7y8PbTwnZOQ1h3DI5W6tD8CCLSlU1A5/Fp1GfcGNnK8gHqsJ9oJSRAwFS1g==",
"requires": {
"@babel/runtime": "^7.6.2"
}
},
"@react-types/shared": {
"version": "3.7.1",
"resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.7.1.tgz",
"integrity": "sha512-VNKlqh37UjB3Hd7gb5Hgsum/2x5mhd7vuBBGPEFevhkOMBW8KlqrU75yaKUe3rEFbky7H6+A8Dzoj4r68OS14w=="
},
"@rushstack/eslint-patch": { "@rushstack/eslint-patch": {
"version": "1.0.6", "version": "1.0.6",
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.0.6.tgz", "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.0.6.tgz",
@ -2786,6 +2946,11 @@
"@types/jest": "*" "@types/jest": "*"
} }
}, },
"@types/warning": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz",
"integrity": "sha1-DSUBJorY+ZYrdA04fEZU9fjiPlI="
},
"@types/yargs": { "@types/yargs": {
"version": "15.0.14", "version": "15.0.14",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz",
@ -2935,6 +3100,15 @@
"eslint-visitor-keys": "^2.0.0" "eslint-visitor-keys": "^2.0.0"
} }
}, },
"@xstate/react": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/@xstate/react/-/react-1.5.1.tgz",
"integrity": "sha512-DJHDqDlZHus08X98uMJw4KR17FRWBXLHMQ02YRxx0DMm5VLn75VwGyt4tXdlNZHQWjyk++C5c9Ichq3PdmM3og==",
"requires": {
"use-isomorphic-layout-effect": "^1.0.0",
"use-subscription": "^1.3.0"
}
},
"abab": { "abab": {
"version": "2.0.5", "version": "2.0.5",
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz",
@ -3800,6 +3974,11 @@
} }
} }
}, },
"body-scroll-lock": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/body-scroll-lock/-/body-scroll-lock-3.1.5.tgz",
"integrity": "sha512-Yi1Xaml0EvNA0OYWxXiYNqY24AfWkbA6w5vxE7GWxtKfzIbZM+Qw+aSmkgsbWzbHiy/RCSkUZBplVxTA+E4jJg=="
},
"boolean": { "boolean": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/boolean/-/boolean-3.1.2.tgz", "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.1.2.tgz",
@ -6973,6 +7152,14 @@
"readable-stream": "^3.1.1" "readable-stream": "^3.1.1"
} }
}, },
"focus-trap": {
"version": "6.6.0",
"resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-6.6.0.tgz",
"integrity": "sha512-2hWVR3XbBejn5v8wDW9DFzLWXcxMNaSJ/CtE3E+FJjjBCLwIYbZJwjUi2RDBfQPM58gHEt5hck0jrJgHR9/s+A==",
"requires": {
"tabbable": "^5.2.0"
}
},
"follow-redirects": { "follow-redirects": {
"version": "1.14.1", "version": "1.14.1",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz",
@ -12382,6 +12569,50 @@
"react-is": "^16.12.0 || ^17.0.0" "react-is": "^16.12.0 || ^17.0.0"
} }
}, },
"react-spring": {
"version": "9.2.4",
"resolved": "https://registry.npmjs.org/react-spring/-/react-spring-9.2.4.tgz",
"integrity": "sha512-bMjbyTW0ZGd+/h9cjtohLqCwOGqX2OuaTvalOVfLCGmhzEg/u3GgopI3LAm4UD2Br3MNdVdGgNVoESg4MGqKFQ==",
"requires": {
"@react-spring/core": "~9.2.0",
"@react-spring/konva": "~9.2.0",
"@react-spring/native": "~9.2.0",
"@react-spring/three": "~9.2.0",
"@react-spring/web": "~9.2.0",
"@react-spring/zdog": "~9.2.0"
}
},
"react-spring-bottom-sheet": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/react-spring-bottom-sheet/-/react-spring-bottom-sheet-3.4.0.tgz",
"integrity": "sha512-zKwTymxrTRMHPjfBiMw8reQlWoVqlCGMTefmMYkAlBvR7n3hBe5sntuQJAEjmrAnA+cLSGp44mtmgBtT2ksL5Q==",
"requires": {
"@juggle/resize-observer": "^3.2.0",
"@reach/portal": "^0.13.0",
"@xstate/react": "^1.2.0",
"body-scroll-lock": "^3.1.5",
"focus-trap": "^6.2.2",
"react-spring": "^8.0.27",
"react-use-gesture": "^8.0.1",
"xstate": "^4.15.1"
},
"dependencies": {
"react-spring": {
"version": "8.0.27",
"resolved": "https://registry.npmjs.org/react-spring/-/react-spring-8.0.27.tgz",
"integrity": "sha512-nDpWBe3ZVezukNRandTeLSPcwwTMjNVu1IDq9qA/AMiUqHuRN4BeSWvKr3eIxxg1vtiYiOLy4FqdfCP5IoP77g==",
"requires": {
"@babel/runtime": "^7.3.1",
"prop-types": "^15.5.8"
}
},
"react-use-gesture": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/react-use-gesture/-/react-use-gesture-8.0.1.tgz",
"integrity": "sha512-CXzUNkulUdgouaAlvAsC5ZVo0fi9KGSBSk81WrE4kOIcJccpANe9zZkAYr5YZZhqpicIFxitsrGVS4wmoMun9A=="
}
}
},
"react-test-renderer": { "react-test-renderer": {
"version": "17.0.1", "version": "17.0.1",
"resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-17.0.1.tgz", "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-17.0.1.tgz",
@ -12400,6 +12631,11 @@
} }
} }
}, },
"react-use-gesture": {
"version": "9.1.3",
"resolved": "https://registry.npmjs.org/react-use-gesture/-/react-use-gesture-9.1.3.tgz",
"integrity": "sha512-CdqA2SmS/fj3kkS2W8ZU8wjTbVBAIwDWaRprX7OKaj7HlGwBasGEFggmk5qNklknqk9zK/h8D355bEJFTpqEMg=="
},
"read-pkg": { "read-pkg": {
"version": "5.2.0", "version": "5.2.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
@ -13962,6 +14198,11 @@
"rename-overwrite": "^3.0.0" "rename-overwrite": "^3.0.0"
} }
}, },
"tabbable": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/tabbable/-/tabbable-5.2.0.tgz",
"integrity": "sha512-0uyt8wbP0P3T4rrsfYg/5Rg3cIJ8Shl1RJ54QMqYxm1TLdWqJD1u6+RQjr2Lor3wmfT7JRHkirIwy99ydBsyPg=="
},
"table": { "table": {
"version": "6.7.1", "version": "6.7.1",
"resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz",
@ -14821,6 +15062,11 @@
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
"integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ=="
}, },
"use-isomorphic-layout-effect": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.1.tgz",
"integrity": "sha512-L7Evj8FGcwo/wpbv/qvSfrkHFtOpCzvM5yl2KVyDJoylVuSvzphiiasmjgQPttIGBAy2WKiBNR98q8w7PiNgKQ=="
},
"use-subscription": { "use-subscription": {
"version": "1.5.1", "version": "1.5.1",
"resolved": "https://registry.npmjs.org/use-subscription/-/use-subscription-1.5.1.tgz", "resolved": "https://registry.npmjs.org/use-subscription/-/use-subscription-1.5.1.tgz",
@ -15144,6 +15390,14 @@
"makeerror": "1.0.x" "makeerror": "1.0.x"
} }
}, },
"warning": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
"integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
"requires": {
"loose-envify": "^1.0.0"
}
},
"watchpack": { "watchpack": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.1.1.tgz", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.1.1.tgz",
@ -15352,6 +15606,11 @@
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
}, },
"xstate": {
"version": "4.23.1",
"resolved": "https://registry.npmjs.org/xstate/-/xstate-4.23.1.tgz",
"integrity": "sha512-8ZoCe8d6wDSPfkep+GBgi+fKAdMyXcaizoNf5FKceEhlso4+9n1TeK6oviaDsXZ3Z5O8xKkJOxXPNuD4cA9LCw=="
},
"xtend": { "xtend": {
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",

View File

@ -59,6 +59,9 @@
"react": "18.0.0-alpha-6f3fcbd6f-20210730", "react": "18.0.0-alpha-6f3fcbd6f-20210730",
"react-dom": "18.0.0-alpha-6f3fcbd6f-20210730", "react-dom": "18.0.0-alpha-6f3fcbd6f-20210730",
"react-hook-form": "7.12.2", "react-hook-form": "7.12.2",
"react-spring": "9.2.4",
"react-spring-bottom-sheet": "3.4.0",
"react-use-gesture": "9.1.3",
"tailwindcss": "2.2.7", "tailwindcss": "2.2.7",
"twilio": "3.66.1", "twilio": "3.66.1",
"zod": "3.5.1" "zod": "3.5.1"