Free CRM Part 2: Client Notes, Dark Mode, Adding Customers

Free CRM Part 2: Client Notes, Dark Mode, Adding Customers

We have a lot of stuff to add to our free CRM software.

Small businesses are counting on us! Small businesses don't want to pay monstrous fees!

Mr. Big Boss the head honcho called. He said he wants improvements! This is what he requested:

  1. His employees are working late nights and requested a Dark Mode.
  2. His employees are tired of writing sticky notes when calling clients and would like notes for each customer.
  3. He is tired of adding customers from the /admin route. Have an option for his employees to add their own customers.

To improve the view with a dark mode, we can use Bulma's dark mode support or add custom CSS to toggle between light and dark themes. There should be a button to toggle the Dark Mode on or off. And it should work across pages.

Here is the new base.html. Notice the JavaScript code for toggling Dark Mode.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CRM</title>
    <link rel="stylesheet" >
    <style>
        body.dark-mode {
            background-color: #121212;
            color: #e0e0e0;
        }
        body.dark-mode .navbar, body.dark-mode .table {
            background-color: #1f1f1f;
            color: #e0e0e0;
        }
        body.dark-mode .input, body.dark-mode .textarea {
            background-color: #2e2e2e;
            color: #e0e0e0;
        }
        .toggle-dark-mode {
            cursor: pointer;
            padding: 5px;
            background-color: #2e2e2e;
            color: #e0e0e0;
            border-radius: 5px;
        }
    </style>
</head>
<body>
    <nav class="navbar">
        <div class="navbar-brand">
            <a class="navbar-item" href="/">CRM</a>
            <span class="toggle-dark-mode" onclick="toggleDarkMode()">Toggle Dark Mode</span>
        </div>
    </nav>
    <section class="section">
        <div class="container">
            {% block content %}
            {% endblock %}
        </div>
    </section>
    <script>
        function toggleDarkMode() {
            document.body.classList.toggle('dark-mode');
            localStorage.setItem('dark-mode', document.body.classList.contains('dark-mode'));
        }

        document.addEventListener('DOMContentLoaded', () => {
            if (localStorage.getItem('dark-mode') === 'true') {
                document.body.classList.add('dark-mode');
            }
        });
    </script>
</body>
</html>        

Next we can update the customer_list.html template.

{% extends "crm/base.html" %}

{% block content %}
<h1 class="title">Customer List</h1>
<a class="button is-primary" href="{% url 'add_customer' %}">Add Customer</a>
<table class="table is-fullwidth">
    <thead>
        <tr>
            <th>Name</th>
            <th>Email</th>
            <th>Phone</th>
            <th>Address</th>
        </tr>
    </thead>
    <tbody>
        {% for customer in customers %}
        <tr>
            <td>{{ customer.name }}</td>
            <td>{{ customer.email }}</td>
            <td>{{ customer.phone }}</td>
            <td>{{ customer.address }}</td>
        </tr>
        {% endfor %}
    </tbody>
</table>
{% endblock %}        

Now we have a nice Dark Mode toggle button to help our eyesight at night time. This can be toggled on the top left.

In order to add notes, we simply edit our model. We create a new class Note. I want to add notes for every customer. I also want to see previous notes. If any of you have used SalesForce you can imagine what this might look like.

Lets edit models.py to include our new class Note.

from django.db import models

class Customer(models.Model):
    name = models.CharField(max_length=255)
    email = models.EmailField(unique=True)
    phone = models.CharField(max_length=20, blank=True)
    address = models.TextField(blank=True)

    def __str__(self):
        return self.name

class Note(models.Model):
    customer = models.ForeignKey(Customer, related_name='notes', on_delete=models.CASCADE)
    text = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"Note for {self.customer.name} at {self.created_at}"        

Create and apply migrations in order to update the database. If we have a new class, we need to update the database.

python manage.py makemigrations crm
python manage.py migrate        

Create a file crm/forms.py for our new Notes class.

from django import forms
from .models import Customer, Note

class CustomerForm(forms.ModelForm):
    class Meta:
        model = Customer
        fields = ['name', 'email', 'phone', 'address']

class NoteForm(forms.ModelForm):
    class Meta:
        model = Note
        fields = ['text']        

Update views.py. While we are here, we need to work on adding customers. This will take input from a form.

# crm/views.py
from django.shortcuts import render, redirect, get_object_or_404
from .models import Customer, Note
from .forms import CustomerForm, NoteForm

def customer_list(request):
    customers = Customer.objects.all()
    return render(request, 'crm/customer_list.html', {'customers': customers})

def add_customer(request):
    if request.method == 'POST':
        form = CustomerForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('customer_list')
    else:
        form = CustomerForm()
    return render(request, 'crm/add_customer.html', {'form': form})

def customer_detail(request, pk):
    customer = get_object_or_404(Customer, pk=pk)
    notes = customer.notes.all()
    if request.method == 'POST':
        form = NoteForm(request.POST)
        if form.is_valid():
            note = form.save(commit=False)
            note.customer = customer
            note.save()
            return redirect('customer_detail', pk=customer.pk)
    else:
        form = NoteForm()
    return render(request, 'crm/customer_detail.html', {'customer': customer, 'notes': notes, 'form': form})        

Update crm/urls.py to have the proper urls. We need an url for adding customers and an url for viewing details.

# crm/urls.py
from django.urls import path
from .views import customer_list, add_customer, customer_detail

urlpatterns = [
    path('', customer_list, name='customer_list'),
    path('add/', add_customer, name='add_customer'),
    path('<int:pk>/', customer_detail, name='customer_detail'),
]        

Now we should add new files to our templates. Here is add_customer.html.

{% extends "crm/base.html" %}

{% block content %}
<h1 class="title">Add Customer</h1>
<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit" class="button is-primary">Add Customer</button>
</form>
{% endblock %}        

And customer_detail.html. This page is for viewing those notes.

{% extends "crm/base.html" %}

{% block content %}
<h1 class="title">{{ customer.name }}</h1>
<p>Email: {{ customer.email }}</p>
<p>Phone: {{ customer.phone }}</p>
<p>Address: {{ customer.address }}</p>

<h2 class="subtitle">Notes</h2>
<ul>
    {% for note in notes %}
    <li>{{ note.created_at }}: {{ note.text }}</li>
    {% endfor %}
</ul>

<h2 class="subtitle">Add Note</h2>
<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit" class="button is-primary">Add Note</button>
</form>
{% endblock %}        

Lets see how it looks. Now this is notes page is viewed over at https://127.0.0.1:8000/1/

I will need to have to edit this a bit so that we can arrive at the proper page. So admire this nice note taking form and lets re-visit customer_list.html.

Edit customer_list.html to tie everything we did today together.

{% extends "crm/base.html" %}

{% block content %}
<h1 class="title">Customer List</h1>
<table class="table is-fullwidth">
    <thead>
        <tr>
            <th>Name</th>
            <th>Email</th>
            <th>Phone</th>
            <th>Address</th>
            <th>Actions</th>
        </tr>
    </thead>
    <tbody>
        {% for customer in customers %}
        <tr>
            <td><a href="{% url 'customer_detail' customer.pk %}">{{ customer.name }}</a></td>
            <td>{{ customer.email }}</td>
            <td>{{ customer.phone }}</td>
            <td>{{ customer.address }}</td>
            <td><a href="{% url 'customer_detail' customer.pk %}">View</a></td>
        </tr>
        {% endfor %}
    </tbody>
</table>
<a class="button is-primary" href="{% url 'add_customer' %}">Add Customer</a>
{% endblock %}        

Now re-load the main page and lets see what happens. It's going to look great.

Ah now I see the view option that takes us to respective notes, and the Add Customer button. Very nice! Also, we can add new customers. I think the new sales department is going to have a great time using this software.

I've added the source code for this free CRM. If you have suggestions let me know about them so i can apply new features. -Henry

CRM github repo

要查看或添加评论,请登录

Henry Meier的更多文章

  • Chess Part 2: Finish The Game

    Chess Part 2: Finish The Game

    Welcome back, today we are working on the Front-End. OK, on to the big boy file.

  • Chess Part 1: Multiplayer

    Chess Part 1: Multiplayer

    It's been quite some time since I was able to write an article. Many of my articles have started to blow up so I…

  • Neural Network in C Part 4: Hidden Layer Analysis

    Neural Network in C Part 4: Hidden Layer Analysis

    I want to look under the hood today. Obviously we can see the input layer and output layer.

  • Neural Network in C Part 3: Assembly VS C

    Neural Network in C Part 3: Assembly VS C

    Our Neural Network is fast but we can make it even faster. We will convert the code to assembly, then race the two side…

    2 条评论
  • Neural Network in C Part 2: C Programming

    Neural Network in C Part 2: C Programming

    In this article, we explore how to build a simple feed forward neural network in C to recognize handwritten digits from…

  • Neural Network in C Part 1: Idea

    Neural Network in C Part 1: Idea

    Welcome, normally I enjoy programming in Python and using the TensorFlow library to create machine learning…

  • Free CRM Part 1: Idea

    Free CRM Part 1: Idea

    Salesforce is expensive. Lets make our own CRM (Customer Relationship Management) software.

  • Firmware Engineering Part 3: OLED Display

    Firmware Engineering Part 3: OLED Display

    The temperature/humidity sensor works. Currently, this device communicates with a website and shares data over MQTT.

  • Firmware Engineering Part 2: Data Logging Website

    Firmware Engineering Part 2: Data Logging Website

    Last article, we wrote a simple MicroPython program for the ESP32. This device broadcasts raw temperature and humidity…

  • Firmware Engineering Part 1: MicroPython

    Firmware Engineering Part 1: MicroPython

    I bet you thought Python was just for data science and web applications. MicroPython is a full implementation of the…

    1 条评论

社区洞察

其他会员也浏览了