style call list page
This commit is contained in:
parent
4bc24f5395
commit
d71e4de033
@ -52,6 +52,14 @@
|
||||
font-display: optional;
|
||||
}
|
||||
|
||||
.divide-y > :first-child {
|
||||
@apply border-t;
|
||||
}
|
||||
|
||||
.divide-y > :last-child:not([hidden]) {
|
||||
@apply border-b;
|
||||
}
|
||||
|
||||
.h1 {
|
||||
@apply text-4xl font-extrabold tracking-tighter;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ export default function ConversationsList() {
|
||||
{Object.values(conversations).map(({ recipient, formattedPhoneNumber, messages }) => {
|
||||
const lastMessage = messages[messages.length - 1]!;
|
||||
return (
|
||||
<li key={recipient} className="py-2 p-4">
|
||||
<li key={`sms-conversation-${recipient}`} className="py-2 px-4">
|
||||
<Link href={Routes.ConversationPage({ recipient })}>
|
||||
<a className="flex flex-col">
|
||||
<div className="flex flex-row justify-between">
|
||||
|
@ -23,7 +23,7 @@ const Messages: BlitzPage = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-col space-y-6 p-6">
|
||||
<div className="flex flex-col space-y-6 p-3">
|
||||
<h2 className="text-3xl font-bold">Messages</h2>
|
||||
</div>
|
||||
<Suspense fallback="Loading...">
|
||||
|
@ -3,6 +3,9 @@ import { Queue } from "quirrel/blitz";
|
||||
import db from "../../../../db";
|
||||
import insertCallsQueue from "./insert-calls";
|
||||
import getTwilioClient from "../../../../integrations/twilio";
|
||||
import appLogger from "../../../../integrations/logger";
|
||||
|
||||
const logger = appLogger.child({ queue: "fetch-calls" });
|
||||
|
||||
type Payload = {
|
||||
organizationId: string;
|
||||
@ -15,7 +18,7 @@ const fetchCallsQueue = Queue<Payload>("api/queue/fetch-calls", async ({ organiz
|
||||
include: { organization: true },
|
||||
});
|
||||
if (!phoneNumber) {
|
||||
console.log("no phone number found");
|
||||
logger.warn(`No phone number found with id=${phoneNumberId}, organizationId=${organizationId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -116,10 +116,9 @@ export default async function incomingCallHandler(req: BlitzApiRequest, res: Bli
|
||||
// TODO dial.client("unique id of device user is picking up with");
|
||||
// TODO send notification
|
||||
// TODO db.phoneCall.create(...);
|
||||
// TODO subscribe to status updates to update duration when call ends
|
||||
}
|
||||
|
||||
// TODO queue job to update duration when call ends
|
||||
|
||||
res.status(500).end();
|
||||
}
|
||||
|
||||
@ -135,3 +134,32 @@ const outgoingBody = {
|
||||
From: "client:95267d60-3d35-4c36-9905-8543ecb4f174__673b461a-11ba-43a4-89d7-9e29403053d4",
|
||||
To: "+33613370787",
|
||||
};
|
||||
|
||||
const incomingBody = {
|
||||
AccountSid: "ACa886d066be0832990d1cf43fb1d53362",
|
||||
ApiVersion: "2010-04-01",
|
||||
ApplicationSid: "APa43d85150ad6f6cf9869fbe1c1e36a66",
|
||||
CallSid: "CA09a5d9a4cfacf2b56d66f8f743d2881a",
|
||||
CallStatus: "ringing",
|
||||
Called: "+33757592025",
|
||||
CalledCity: "",
|
||||
CalledCountry: "FR",
|
||||
CalledState: "",
|
||||
CalledZip: "",
|
||||
Caller: "+33613370787",
|
||||
CallerCity: "",
|
||||
CallerCountry: "FR",
|
||||
CallerState: "",
|
||||
CallerZip: "",
|
||||
Direction: "inbound",
|
||||
From: "+33613370787",
|
||||
FromCity: "",
|
||||
FromCountry: "FR",
|
||||
FromState: "",
|
||||
FromZip: "",
|
||||
To: "+33757592025",
|
||||
ToCity: "",
|
||||
ToCountry: "FR",
|
||||
ToState: "",
|
||||
ToZip: "",
|
||||
};
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { PhoneMissedCallIcon, PhoneOutgoingIcon } from "@heroicons/react/solid";
|
||||
|
||||
import { Direction } from "../../../db";
|
||||
import usePhoneCalls from "../hooks/use-phone-calls";
|
||||
import { formatRelativeDate } from "../../core/helpers/date-formatter";
|
||||
import clsx from "clsx";
|
||||
|
||||
export default function PhoneCallsList() {
|
||||
const phoneCalls = usePhoneCalls()[0];
|
||||
@ -11,11 +15,27 @@ export default function PhoneCallsList() {
|
||||
return (
|
||||
<ul className="divide-y">
|
||||
{phoneCalls.map((phoneCall) => {
|
||||
const recipient = Direction.Outbound ? phoneCall.to : phoneCall.from;
|
||||
const isOutboundCall = phoneCall.direction === Direction.Outbound;
|
||||
const isMissedCall = !isOutboundCall && phoneCall.duration === "0"; // TODO
|
||||
const recipient = isOutboundCall
|
||||
? phoneCall.toMeta.formattedPhoneNumber
|
||||
: phoneCall.fromMeta.formattedPhoneNumber;
|
||||
return (
|
||||
<li key={phoneCall.id} className="flex flex-row justify-between py-2">
|
||||
<div>{recipient}</div>
|
||||
<div>{new Date(phoneCall.createdAt).toLocaleString("en-US")}</div>
|
||||
<li key={phoneCall.id} className="flex flex-row py-2 px-4 ml-12">
|
||||
<div className="h-4 w-4 mt-1 -ml-12">
|
||||
{isOutboundCall ? <PhoneOutgoingIcon className="text-[#C4C4C6]" /> : null}
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-start justify-center ml-4">
|
||||
<strong className={clsx(isMissedCall && "text-[#FF362A]")}>{recipient}</strong>
|
||||
<span className="text-[#89898C] text-sm">
|
||||
{isOutboundCall ? phoneCall.toMeta.country : phoneCall.fromMeta.country}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<span className="text-[#89898C] text-sm self-center ml-auto">
|
||||
{formatRelativeDate(new Date(phoneCall.createdAt))}
|
||||
</span>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
|
@ -11,7 +11,7 @@ const PhoneCalls: BlitzPage = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-col space-y-6 p-6">
|
||||
<div className="flex flex-col space-y-6 py-3 pl-12">
|
||||
<h2 className="text-3xl font-bold">Calls</h2>
|
||||
</div>
|
||||
<Suspense fallback="Loading...">
|
||||
|
@ -25,7 +25,6 @@ const KeypadPage: BlitzPage = () => {
|
||||
const longPressDigit = useAtom(longPressDigitAtom)[1];
|
||||
const onZeroPressProps = {
|
||||
onPressStart() {
|
||||
console.log("0");
|
||||
pressDigit("0");
|
||||
timeoutRef.current = setTimeout(() => {
|
||||
longPressDigit("+");
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { resolver } from "blitz";
|
||||
import { z } from "zod";
|
||||
import PhoneNumber from "awesome-phonenumber";
|
||||
|
||||
import db, { Prisma } from "db";
|
||||
|
||||
const Body = z.object({
|
||||
@ -8,9 +10,272 @@ const Body = z.object({
|
||||
|
||||
export default resolver.pipe(resolver.zod(Body), resolver.authorize(), async ({ phoneNumberId }, context) => {
|
||||
const organizationId = context.session.orgId;
|
||||
|
||||
return db.phoneCall.findMany({
|
||||
const phoneCalls = await db.phoneCall.findMany({
|
||||
where: { organizationId, phoneNumberId },
|
||||
orderBy: { createdAt: Prisma.SortOrder.desc },
|
||||
});
|
||||
|
||||
return phoneCalls.map((phoneCall) => ({
|
||||
...phoneCall,
|
||||
fromMeta: getPhoneNumberMeta(phoneCall.from),
|
||||
toMeta: getPhoneNumberMeta(phoneCall.to),
|
||||
}));
|
||||
});
|
||||
|
||||
function getPhoneNumberMeta(rawPhoneNumber: string) {
|
||||
const phoneNumber = new PhoneNumber(rawPhoneNumber);
|
||||
const formattedPhoneNumber =
|
||||
phoneNumber.getNumber("international") ?? phoneNumber.getNumber("national") ?? rawPhoneNumber;
|
||||
|
||||
return {
|
||||
formattedPhoneNumber,
|
||||
country: countries[phoneNumber.getRegionCode()] ?? "unknown",
|
||||
};
|
||||
}
|
||||
|
||||
const countries: Record<string, string> = {
|
||||
AF: "Afghanistan",
|
||||
AL: "Albania",
|
||||
DZ: "Algeria",
|
||||
AS: "American Samoa",
|
||||
AD: "Andorra",
|
||||
AO: "Angola",
|
||||
AI: "Anguilla",
|
||||
AQ: "Antarctica",
|
||||
AG: "Antigua and Barbuda",
|
||||
AR: "Argentina",
|
||||
AM: "Armenia",
|
||||
AW: "Aruba",
|
||||
AU: "Australia",
|
||||
AT: "Austria",
|
||||
AZ: "Azerbaijan",
|
||||
BS: "Bahamas",
|
||||
BH: "Bahrain",
|
||||
BD: "Bangladesh",
|
||||
BB: "Barbados",
|
||||
BY: "Belarus",
|
||||
BE: "Belgium",
|
||||
BZ: "Belize",
|
||||
BJ: "Benin",
|
||||
BM: "Bermuda",
|
||||
BT: "Bhutan",
|
||||
BO: "Bolivia",
|
||||
BA: "Bosnia and Herzegovina",
|
||||
BW: "Botswana",
|
||||
BV: "Bouvet Island",
|
||||
BR: "Brazil",
|
||||
IO: "British Indian Ocean Territory",
|
||||
BN: "Brunei",
|
||||
BG: "Bulgaria",
|
||||
BF: "Burkina Faso",
|
||||
BI: "Burundi",
|
||||
KH: "Cambodia",
|
||||
CM: "Cameroon",
|
||||
CA: "Canada",
|
||||
CV: "Cape Verde",
|
||||
KY: "Cayman Islands",
|
||||
CF: "Central African Republic",
|
||||
TD: "Chad",
|
||||
CL: "Chile",
|
||||
CN: "China",
|
||||
CX: "Christmas Island",
|
||||
CC: "Cocos (Keeling) Islands",
|
||||
CO: "Colombia",
|
||||
KM: "Comoros",
|
||||
CG: "Congo",
|
||||
CD: "Congo, the Democratic Republic of the",
|
||||
CK: "Cook Islands",
|
||||
CR: "Costa Rica",
|
||||
CI: "Ivory Coast",
|
||||
HR: "Croatia",
|
||||
CU: "Cuba",
|
||||
CY: "Cyprus",
|
||||
CZ: "Czech Republic",
|
||||
DK: "Denmark",
|
||||
DJ: "Djibouti",
|
||||
DM: "Dominica",
|
||||
DO: "Dominican Republic",
|
||||
EC: "Ecuador",
|
||||
EG: "Egypt",
|
||||
SV: "El Salvador",
|
||||
GQ: "Equatorial Guinea",
|
||||
ER: "Eritrea",
|
||||
EE: "Estonia",
|
||||
ET: "Ethiopia",
|
||||
FK: "Falkland Islands (Malvinas)",
|
||||
FO: "Faroe Islands",
|
||||
FJ: "Fiji",
|
||||
FI: "Finland",
|
||||
FR: "France",
|
||||
GF: "French Guiana",
|
||||
PF: "French Polynesia",
|
||||
TF: "French Southern Territories",
|
||||
GA: "Gabon",
|
||||
GM: "Gambia",
|
||||
GE: "Georgia",
|
||||
DE: "Germany",
|
||||
GH: "Ghana",
|
||||
GI: "Gibraltar",
|
||||
GR: "Greece",
|
||||
GL: "Greenland",
|
||||
GD: "Grenada",
|
||||
GP: "Guadeloupe",
|
||||
GU: "Guam",
|
||||
GT: "Guatemala",
|
||||
GG: "Guernsey",
|
||||
GN: "Guinea",
|
||||
GW: "Guinea-Bissau",
|
||||
GY: "Guyana",
|
||||
HT: "Haiti",
|
||||
HM: "Heard Island and McDonald Islands",
|
||||
VA: "Holy See (Vatican City State)",
|
||||
HN: "Honduras",
|
||||
HK: "Hong Kong",
|
||||
HU: "Hungary",
|
||||
IS: "Iceland",
|
||||
IN: "India",
|
||||
ID: "Indonesia",
|
||||
IR: "Iran, Islamic Republic of",
|
||||
IQ: "Iraq",
|
||||
IE: "Ireland",
|
||||
IM: "Isle of Man",
|
||||
IL: "Israel",
|
||||
IT: "Italy",
|
||||
JM: "Jamaica",
|
||||
JP: "Japan",
|
||||
JE: "Jersey",
|
||||
JO: "Jordan",
|
||||
KZ: "Kazakhstan",
|
||||
KE: "Kenya",
|
||||
KI: "Kiribati",
|
||||
KP: "Korea, Democratic People's Republic of",
|
||||
KR: "South Korea",
|
||||
KW: "Kuwait",
|
||||
KG: "Kyrgyzstan",
|
||||
LA: "Lao People's Democratic Republic",
|
||||
LV: "Latvia",
|
||||
LB: "Lebanon",
|
||||
LS: "Lesotho",
|
||||
LR: "Liberia",
|
||||
LY: "Libya",
|
||||
LI: "Liechtenstein",
|
||||
LT: "Lithuania",
|
||||
LU: "Luxembourg",
|
||||
MO: "Macao",
|
||||
MK: "Macedonia, the former Yugoslav Republic of",
|
||||
MG: "Madagascar",
|
||||
MW: "Malawi",
|
||||
MY: "Malaysia",
|
||||
MV: "Maldives",
|
||||
ML: "Mali",
|
||||
MT: "Malta",
|
||||
MH: "Marshall Islands",
|
||||
MQ: "Martinique",
|
||||
MR: "Mauritania",
|
||||
MU: "Mauritius",
|
||||
YT: "Mayotte",
|
||||
MX: "Mexico",
|
||||
FM: "Micronesia, Federated States of",
|
||||
MD: "Moldova, Republic of",
|
||||
MC: "Monaco",
|
||||
MN: "Mongolia",
|
||||
ME: "Montenegro",
|
||||
MS: "Montserrat",
|
||||
MA: "Morocco",
|
||||
MZ: "Mozambique",
|
||||
MM: "Burma",
|
||||
NA: "Namibia",
|
||||
NR: "Nauru",
|
||||
NP: "Nepal",
|
||||
NL: "Netherlands",
|
||||
AN: "Netherlands Antilles",
|
||||
NC: "New Caledonia",
|
||||
NZ: "New Zealand",
|
||||
NI: "Nicaragua",
|
||||
NE: "Niger",
|
||||
NG: "Nigeria",
|
||||
NU: "Niue",
|
||||
NF: "Norfolk Island",
|
||||
MP: "Northern Mariana Islands",
|
||||
NO: "Norway",
|
||||
OM: "Oman",
|
||||
PK: "Pakistan",
|
||||
PW: "Palau",
|
||||
PS: "Palestinian Territory, Occupied",
|
||||
PA: "Panama",
|
||||
PG: "Papua New Guinea",
|
||||
PY: "Paraguay",
|
||||
PE: "Peru",
|
||||
PH: "Philippines",
|
||||
PN: "Pitcairn",
|
||||
PL: "Poland",
|
||||
PT: "Portugal",
|
||||
PR: "Puerto Rico",
|
||||
QA: "Qatar",
|
||||
RE: "Réunion",
|
||||
RO: "Romania",
|
||||
RU: "Russia",
|
||||
RW: "Rwanda",
|
||||
SH: "Saint Helena, Ascension and Tristan da Cunha",
|
||||
KN: "Saint Kitts and Nevis",
|
||||
LC: "Saint Lucia",
|
||||
PM: "Saint Pierre and Miquelon",
|
||||
VC: "St. Vincent and the Grenadines",
|
||||
WS: "Samoa",
|
||||
SM: "San Marino",
|
||||
ST: "Sao Tome and Principe",
|
||||
SA: "Saudi Arabia",
|
||||
SN: "Senegal",
|
||||
RS: "Serbia",
|
||||
SC: "Seychelles",
|
||||
SL: "Sierra Leone",
|
||||
SG: "Singapore",
|
||||
SK: "Slovakia",
|
||||
SI: "Slovenia",
|
||||
SB: "Solomon Islands",
|
||||
SO: "Somalia",
|
||||
ZA: "South Africa",
|
||||
GS: "South Georgia and the South Sandwich Islands",
|
||||
SS: "South Sudan",
|
||||
ES: "Spain",
|
||||
LK: "Sri Lanka",
|
||||
SD: "Sudan",
|
||||
SR: "Suriname",
|
||||
SJ: "Svalbard and Jan Mayen",
|
||||
SZ: "Swaziland",
|
||||
SE: "Sweden",
|
||||
CH: "Switzerland",
|
||||
SY: "Syrian Arab Republic",
|
||||
TW: "Taiwan",
|
||||
TJ: "Tajikistan",
|
||||
TZ: "Tanzania, United Republic of",
|
||||
TH: "Thailand",
|
||||
TL: "Timor-Leste",
|
||||
TG: "Togo",
|
||||
TK: "Tokelau",
|
||||
TO: "Tonga",
|
||||
TT: "Trinidad and Tobago",
|
||||
TN: "Tunisia",
|
||||
TR: "Turkey",
|
||||
TM: "Turkmenistan",
|
||||
TC: "Turks and Caicos Islands",
|
||||
TV: "Tuvalu",
|
||||
UG: "Uganda",
|
||||
UA: "Ukraine",
|
||||
AE: "United Arab Emirates",
|
||||
GB: "United Kingdom",
|
||||
US: "United States",
|
||||
UM: "United States Minor Outlying Islands",
|
||||
UY: "Uruguay",
|
||||
UZ: "Uzbekistan",
|
||||
VU: "Vanuatu",
|
||||
VE: "Venezuela",
|
||||
VN: "Vietnam",
|
||||
VG: "Virgin Islands, British",
|
||||
VI: "Virgin Islands, U.S.",
|
||||
WF: "Wallis and Futuna",
|
||||
EH: "Western Sahara",
|
||||
YE: "Yemen",
|
||||
ZM: "Zambia",
|
||||
ZW: "Zimbabwe",
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user