The Palos Publishing Company

Follow Us On The X Platform @PalosPublishing
Categories We Write About

Build a mini personal CRM

Building a mini personal CRM (Customer Relationship Management system) helps you track contacts, communication history, follow-ups, and notes. Here’s a simple but effective version built using modern web technologies. This CRM will allow you to:

  • Add and edit contacts

  • Store notes and follow-up dates

  • Filter or search contacts

  • Mark contacts as “priority” or “follow-up needed”

Here’s a minimal version using React + Tailwind CSS:


Mini Personal CRM – Code (React + Tailwind)

tsx
// Filename: PersonalCRM.tsx import React, { useState } from 'react'; import { Card, CardContent } from '@/components/ui/card'; import { Input } from '@/components/ui/input'; import { Button } from '@/components/ui/button'; import { Textarea } from '@/components/ui/textarea'; import { Calendar } from 'lucide-react'; type Contact = { id: number; name: string; email: string; phone: string; notes: string; followUpDate?: string; priority: boolean; }; export default function PersonalCRM() { const [contacts, setContacts] = useState<Contact[]>([]); const [newContact, setNewContact] = useState<Contact>({ id: Date.now(), name: '', email: '', phone: '', notes: '', followUpDate: '', priority: false, }); const [search, setSearch] = useState(''); const handleAddContact = () => { if (!newContact.name) return; setContacts([...contacts, { ...newContact, id: Date.now() }]); setNewContact({ id: Date.now(), name: '', email: '', phone: '', notes: '', followUpDate: '', priority: false, }); }; const handleTogglePriority = (id: number) => { setContacts(prev => prev.map(c => (c.id === id ? { ...c, priority: !c.priority } : c)) ); }; const filteredContacts = contacts.filter(c => c.name.toLowerCase().includes(search.toLowerCase()) ); return ( <div className="p-4 max-w-4xl mx-auto"> <h1 className="text-3xl font-bold mb-6">Mini Personal CRM</h1> <div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> <Input placeholder="Search contacts..." value={search} onChange={e => setSearch(e.target.value)} /> <Card> <CardContent className="space-y-2 p-4"> <Input placeholder="Name" value={newContact.name} onChange={e => setNewContact({ ...newContact, name: e.target.value })} /> <Input placeholder="Email" value={newContact.email} onChange={e => setNewContact({ ...newContact, email: e.target.value })} /> <Input placeholder="Phone" value={newContact.phone} onChange={e => setNewContact({ ...newContact, phone: e.target.value })} /> <Textarea placeholder="Notes" value={newContact.notes} onChange={e => setNewContact({ ...newContact, notes: e.target.value })} /> <div className="flex items-center gap-2"> <Input type="date" value={newContact.followUpDate} onChange={e => setNewContact({ ...newContact, followUpDate: e.target.value })} /> <Calendar className="w-4 h-4 text-gray-500" /> </div> <div className="flex items-center gap-2"> <input type="checkbox" checked={newContact.priority} onChange={() => setNewContact({ ...newContact, priority: !newContact.priority }) } /> <label>Priority</label> </div> <Button onClick={handleAddContact}>Add Contact</Button> </CardContent> </Card> </div> <div className="grid gap-4"> {filteredContacts.map(contact => ( <Card key={contact.id} className="relative"> <CardContent className="p-4 space-y-2"> <div className="flex justify-between"> <h2 className="text-xl font-semibold">{contact.name}</h2> {contact.priority && ( <span className="text-red-500 font-semibold">★ Priority</span> )} </div> <p className="text-sm text-gray-600">📧 {contact.email}</p> <p className="text-sm text-gray-600">📱 {contact.phone}</p> <p className="text-sm">📝 {contact.notes}</p> {contact.followUpDate && ( <p className="text-sm text-blue-600"> 🔔 Follow up: {contact.followUpDate} </p> )} <Button variant="secondary" onClick={() => handleTogglePriority(contact.id)} > Toggle Priority </Button> </CardContent> </Card> ))} </div> </div> ); }

Features Summary

  • Add contact with name, email, phone, notes, follow-up date

  • Mark contact as Priority

  • Search contacts by name

  • Responsive UI using Tailwind

  • Simple data handling with local state (no backend)


Optional Enhancements

You can expand this CRM by adding:

  • Persistent storage using localStorage or a backend (Firebase, Supabase)

  • Tags or categories

  • Reminder emails or notifications

  • Dark mode toggle

  • Export contacts as CSV

Would you like a version using another framework (e.g., Next.js, Vue, Django)?

Share this Page your favorite way: Click any app below to share.

Enter your email below to join The Palos Publishing Company Email List

We respect your email privacy

Categories We Write About