Implement SMS message sending

This commit implements the functionality to send an SMS message from a user's cell phone and display it on the dashboard.  The implementation details are not specified in this commit message.
This commit is contained in:
gpt-engineer-app[bot] 2025-02-26 17:05:52 +00:00
parent add47667af
commit ce57fdd5c6
3 changed files with 75 additions and 30 deletions

8
package-lock.json generated
View file

@ -41,7 +41,7 @@
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"cmdk": "^1.0.0", "cmdk": "^1.0.0",
"date-fns": "^3.6.0", "date-fns": "^4.1.0",
"embla-carousel-react": "^8.3.0", "embla-carousel-react": "^8.3.0",
"input-otp": "^1.2.4", "input-otp": "^1.2.4",
"lucide-react": "^0.462.0", "lucide-react": "^0.462.0",
@ -4196,9 +4196,9 @@
} }
}, },
"node_modules/date-fns": { "node_modules/date-fns": {
"version": "3.6.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz",
"integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
"license": "MIT", "license": "MIT",
"funding": { "funding": {
"type": "github", "type": "github",

View file

@ -44,7 +44,7 @@
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"cmdk": "^1.0.0", "cmdk": "^1.0.0",
"date-fns": "^3.6.0", "date-fns": "^4.1.0",
"embla-carousel-react": "^8.3.0", "embla-carousel-react": "^8.3.0",
"input-otp": "^1.2.4", "input-otp": "^1.2.4",
"lucide-react": "^0.462.0", "lucide-react": "^0.462.0",

View file

@ -1,42 +1,87 @@
import { User } from "lucide-react"; import { User } from "lucide-react";
import { Card } from "@/components/ui/card"; import { Card } from "@/components/ui/card";
import { useQuery } from "@tanstack/react-query";
import { createClient } from "@supabase/supabase-js";
import { formatDistanceToNow } from "date-fns";
interface Conversation { // Initialize Supabase client
id: string; const supabaseUrl = "https://ikmbnngahzcellthaysf.supabase.co";
contact: string; const supabaseAnonKey = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImlrbWJubmdhaHpjZWxsdGhheXNmIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDA1ODY5NjUsImV4cCI6MjA1NjE2Mjk2NX0.puDSeLAaTirOPyj6ndF2Mzzu8CKxlwJsoFP6gK8cWuA";
lastMessage: string;
timestamp: string; if (!supabaseUrl || !supabaseAnonKey) {
throw new Error('Supabase URL and Anon Key are required');
} }
const mockConversations: Conversation[] = [ const supabase = createClient(supabaseUrl, supabaseAnonKey);
{
id: "1", interface Message {
contact: "+1 (555) 987-6543", id: string;
lastMessage: "Thanks for your message", phone_number: string;
timestamp: "2 min ago", message: string;
}, created_at: string;
{ }
id: "2",
contact: "+1 (555) 876-5432",
lastMessage: "I'll get back to you shortly",
timestamp: "1 hour ago",
},
];
export function ConversationList() { export function ConversationList() {
const { data: messages, isLoading } = useQuery({
queryKey: ['messages'],
queryFn: async () => {
const { data, error } = await supabase
.from('messages')
.select('*')
.order('created_at', { ascending: false });
if (error) {
console.error('Error fetching messages:', error);
throw error;
}
return data as Message[];
},
refetchInterval: 5000 // Refetch every 5 seconds
});
// Subscribe to new messages
React.useEffect(() => {
const subscription = supabase
.channel('messages')
.on('postgres_changes', {
event: '*',
schema: 'public',
table: 'messages'
}, () => {
// Trigger a refetch when new messages arrive
queryClient.invalidateQueries({ queryKey: ['messages'] });
})
.subscribe();
return () => {
subscription.unsubscribe();
};
}, []);
if (isLoading) {
return (
<div className="p-4">
<p className="text-muted-foreground">Loading conversations...</p>
</div>
);
}
const conversations = messages || [];
return ( return (
<div className="space-y-4 p-4 animate-fadeIn"> <div className="space-y-4 p-4 animate-fadeIn">
<div className="flex items-center justify-between mb-6"> <div className="flex items-center justify-between mb-6">
<h2 className="text-2xl font-semibold tracking-tight">Conversations</h2> <h2 className="text-2xl font-semibold tracking-tight">Conversations</h2>
<span className="text-sm text-muted-foreground"> <span className="text-sm text-muted-foreground">
{mockConversations.length} active {conversations.length} active
</span> </span>
</div> </div>
<div className="grid gap-4"> <div className="grid gap-4">
{mockConversations.map((conversation) => ( {conversations.map((message) => (
<Card <Card
key={conversation.id} key={message.id}
className="p-4 transition-all hover:shadow-md cursor-pointer group" className="p-4 transition-all hover:shadow-md cursor-pointer group"
> >
<div className="flex items-center space-x-4"> <div className="flex items-center space-x-4">
@ -45,13 +90,13 @@ export function ConversationList() {
</div> </div>
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<div className="flex justify-between items-start"> <div className="flex justify-between items-start">
<h3 className="font-medium truncate">{conversation.contact}</h3> <h3 className="font-medium truncate">{message.phone_number}</h3>
<span className="text-xs text-muted-foreground whitespace-nowrap ml-2"> <span className="text-xs text-muted-foreground whitespace-nowrap ml-2">
{conversation.timestamp} {formatDistanceToNow(new Date(message.created_at), { addSuffix: true })}
</span> </span>
</div> </div>
<p className="text-sm text-muted-foreground truncate"> <p className="text-sm text-muted-foreground truncate">
{conversation.lastMessage} {message.message}
</p> </p>
</div> </div>
</div> </div>