base setup

This commit is contained in:
2026-01-07 12:09:20 +05:30
commit 0c275efea1
278 changed files with 11228 additions and 0 deletions

View File

@@ -0,0 +1,75 @@
{% extends "public_base.html" %}
{% block content %}
<div class="form-content my-3 p-3">
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-5">
<div class="card shadow-lg border-0 rounded-lg mt-0 mb-3">
<div class="card-header justify-content-center">
<h3 class="font-weight-light my-4 text-center">Change Your Password</h3>
</div>
{% if form.errors %}
<div class="alert alert-danger alert-dismissible" role="alert">
<div id="form_errors">
{% for key, value in form.errors.items %}
<strong>{{ value }}</strong>
{% endfor %}
</div>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
{% endif %}
<div class="card-body">
<form method="POST">
{% csrf_token %}
<div class="form-row">
<div class="col-md-10 offset-md-1">
<div class="form-group">
<label class="small mb-1" for="id_old_password">Old Password</label>
<input type="password" name="old_password" autocomplete="new-password"
class="form-control" required id="id_old_password"
placeholder="Enter Old Password"/>
<span>
</span>
</div>
</div>
</div>
<div class="form-row">
<div class="col-md-10 offset-md-1">
<div class="form-group">
<label class="small mb-1" for="id_new_password1">New Password</label>
<input type="password" name="new_password1" autocomplete="new-password"
class="form-control" required id="id_new_password1"
placeholder="Enter New Password"/>
<span>
</span>
</div>
</div>
</div>
<div class="form-row">
<div class="col-md-10 offset-md-1">
<div class="form-group">
<label class="small mb-1" for="id_new_password2">New Password Confirmation</label>
<input type="password" name="new_password2" autocomplete="new-password"
required id="id_new_password2" class="form-control"
placeholder="Confirm New Password"/>
</div>
</div>
</div>
<div class="form-row">
<div class="col-md-10 offset-md-1">
<div class="form-group mt-0 mb-1">
<button type="submit" class="col-md-12 btn btn-dark" id="reset">Update Password</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock content %}

View File

@@ -0,0 +1,596 @@
{% extends 'public_base.html' %}
{% block title %}
Login
{% endblock %}
{% block content %}
{% load static %}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">
<style>
:root {
--primary: #6366f1;
--accent: #4f46e5;
--gradient-start: #6366f1;
--gradient-end: #8b5cf6;
--bg: #ffffff;
--muted: #6b7280;
--danger: #ef4444;
--success: #10b981;
--radius: 16px;
--shadow: 0 20px 40px rgba(99, 102, 241, 0.15);
--shadow-hover: 0 25px 50px rgba(99, 102, 241, 0.25);
}
body {
font-family: 'Inter', sans-serif;
margin: 0;
padding: 0;
background: linear-gradient(135deg, #f0f4ff 0%, #fdf2ff 50%, #f0fdf4 100%);
min-height: 100vh;
}
.login-page {
display: flex;
min-height: 100vh;
align-items: center;
justify-content: center;
padding: 2rem;
position: relative;
overflow: hidden;
}
.login-page::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: radial-gradient(circle, rgba(99, 102, 241, 0.05) 0%, transparent 70%);
animation: float 20s ease-in-out infinite;
}
@keyframes float {
0%, 100% { transform: translate(0, 0) rotate(0deg); }
25% { transform: translate(10px, 10px) rotate(1deg); }
50% { transform: translate(-5px, 15px) rotate(-1deg); }
75% { transform: translate(15px, -5px) rotate(1deg); }
}
.login-container {
display: flex;
max-width: 1200px;
width: 100%;
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20px);
border-radius: var(--radius);
box-shadow: var(--shadow);
overflow: hidden;
border: 1px solid rgba(255, 255, 255, 0.2);
position: relative;
z-index: 1;
}
.login-left {
flex: 1;
padding: 4rem 3rem;
background: white;
position: relative;
}
.login-left::before {
content: '';
position: absolute;
top: 0;
right: 0;
width: 4px;
height: 100%;
background: linear-gradient(to bottom, var(--gradient-start), var(--gradient-end));
}
.form-container {
max-width: 400px;
margin: 0 auto;
}
.logo-section {
text-align: center;
margin-bottom: 2.5rem;
}
.logo {
width: 60px;
height: 60px;
background: linear-gradient(135deg, var(--gradient-start), var(--gradient-end));
border-radius: 16px;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 1rem;
box-shadow: 0 10px 25px rgba(99, 102, 241, 0.3);
}
.logo i {
font-size: 1.8rem;
color: white;
}
.form-container h3 {
margin-bottom: 0.5rem;
font-size: 2rem;
font-weight: 800;
background: linear-gradient(135deg, var(--gradient-start), var(--gradient-end));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
text-align: center;
}
.form-container p.subtext {
margin-bottom: 2.5rem;
font-size: 1rem;
color: var(--muted);
text-align: center;
line-height: 1.6;
}
.form-group {
margin-bottom: 1.5rem;
position: relative;
}
.form-label {
display: block;
margin-bottom: 0.5rem;
font-size: 0.9rem;
font-weight: 600;
color: #374151;
}
.input-group {
position: relative;
}
.form-control {
width: 100%;
padding: 1rem 1rem 1rem 3rem;
border: 2px solid #e5e7eb;
border-radius: 12px;
font-size: 1rem;
transition: all 0.3s ease;
background: #fafafa;
}
.form-control:focus {
border-color: var(--accent);
background: white;
box-shadow: 0 0 0 4px rgba(99, 102, 241, 0.1);
outline: none;
transform: translateY(-2px);
}
.input-icon {
position: absolute;
left: 1rem;
top: 50%;
transform: translateY(-50%);
color: var(--muted);
transition: all 0.3s ease;
}
.form-control:focus + .input-icon {
color: var(--accent);
}
.form-options {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2rem;
}
.remember-me {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.9rem;
color: var(--muted);
}
.forgot-password {
color: var(--accent);
text-decoration: none;
font-size: 0.9rem;
font-weight: 500;
}
.forgot-password:hover {
color: var(--gradient-end);
text-decoration: underline;
}
.btn-submit {
background: linear-gradient(135deg, var(--gradient-start), var(--gradient-end));
color: white;
border: none;
padding: 1rem 2rem;
width: 100%;
border-radius: 12px;
font-weight: 600;
font-size: 1rem;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 10px 25px rgba(99, 102, 241, 0.3);
position: relative;
overflow: hidden;
}
.btn-submit:hover {
transform: translateY(-3px);
box-shadow: var(--shadow-hover);
}
/* OTP Button */
.btn-otp {
background: linear-gradient(135deg, #10b981, #059669);
margin-top: 1rem;
}
.btn-otp:hover {
background: linear-gradient(135deg, #059669, #047857);
transform: translateY(-3px);
box-shadow: var(--shadow-hover);
}
.signup-link {
text-align: center;
font-size: 0.9rem;
color: var(--muted);
margin-top: 1.5rem;
}
.signup-link a {
color: var(--accent);
font-weight: 600;
}
.login-right {
flex: 1;
background: linear-gradient(135deg, var(--gradient-start), var(--gradient-end));
padding: 4rem 3rem;
color: white;
display: flex;
flex-direction: column;
justify-content: center;
position: relative;
overflow: hidden;
}
.login-right::before {
content: '';
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><pattern id="grid" width="10" height="10" patternUnits="userSpaceOnUse"><path d="M 10 0 L 0 0 0 10" fill="none" stroke="rgba(255,255,255,0.1)" stroke-width="0.5"/></pattern></defs><rect width="100" height="100" fill="url(%23grid)"/></svg>');
}
.features-title {
font-size: 2rem;
font-weight: 700;
margin-bottom: 2rem;
}
.feature-item {
display: flex;
align-items: flex-start;
margin-bottom: 1.5rem;
}
.feature-icon {
width: 24px;
height: 24px;
background: rgba(255,255,255,0.2);
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 1rem;
flex-shrink: 0;
}
.alert {
padding: 1rem 1.5rem;
margin-bottom: 1.5rem;
border-radius: 12px;
font-size: 0.9rem;
border-left: 4px solid;
}
.alert-success { background: rgba(16,185,129,0.1); border-color: var(--success); color: #065f46; }
.alert-danger { background: rgba(239,68,68,0.1); border-color: var(--danger); color: #991b1b; }
/* Modal Styles (No Bootstrap) */
.otp-modal {
display: none;
position: fixed;
top: 0; left: 0; width: 100%; height: 100%;
background: rgba(0,0,0,0.5);
z-index: 1000;
align-items: center;
justify-content: center;
}
.otp-modal.active {
display: flex;
}
.otp-modal-content {
background: white;
border-radius: 16px;
box-shadow: var(--shadow);
width: 90%;
max-width: 480px;
overflow: hidden;
}
.otp-modal-header {
padding: 1.5rem 2rem;
border-bottom: 1px solid #e5e7eb;
display: flex;
justify-content: space-between;
align-items: center;
}
.otp-modal-body {
padding: 2rem;
}
.otp-input-group {
display: flex;
gap: 12px;
justify-content: center;
margin: 1.5rem 0;
}
.otp-input {
width: 56px;
height: 64px;
text-align: center;
font-size: 1.8rem;
font-weight: bold;
border: 2px solid #e5e7eb;
border-radius: 12px;
}
.otp-input:focus {
border-color: var(--accent);
box-shadow: 0 0 0 4px rgba(99,102,241,0.1);
outline: none;
}
@media (max-width: 768px) {
.login-container { flex-direction: column; max-width: 500px; }
.login-left::before { display: none; }
.login-right { display: none; }
.login-left { padding: 3rem 2rem; }
}
</style>
<div class="login-page">
<div class="login-container">
<div class="login-left">
<div class="form-container">
<div class="logo-section">
<div class="logo">
<i class="fas fa-shield-alt"></i>
</div>
<h3>Welcome Back</h3>
<p class="subtext">Sign in to your account to continue</p>
</div>
{% if messages %}
{% for message in messages %}
<div class="alert {% if 'success' in message.tags %}alert-success{% else %}alert-danger{% endif %}">
{{ message }}
</div>
{% endfor %}
{% endif %}
<form method="POST" action="{% url 'login' %}">
{% csrf_token %}
<input type="hidden" name="next" value="{{ request.GET.next }}">
<div class="form-group">
<label class="form-label" for="username">Username</label>
<div class="input-group">
<input id="username" name="username" class="form-control" placeholder="Enter your username" required autofocus type="text">
<div class="input-icon"><i class="fas fa-user"></i></div>
</div>
</div>
<div class="form-group">
<label class="form-label" for="password">Password</label>
<div class="input-group">
<input type="password" id="password" name="password" class="form-control" placeholder="Enter your password" required>
<div class="input-icon"><i class="fas fa-lock"></i></div>
</div>
</div>
<div class="form-options">
<label class="remember-me">
<input type="checkbox" name="remember"> Remember me
</label>
<a href="{% url 'password_reset' %}" class="forgot-password">Forgot password?</a>
</div>
<button type="submit" class="btn-submit">
<i class="fas fa-sign-in-alt"></i> Sign In
</button>
<button type="button" class="btn-submit btn-otp" id="openOtpModal">
<i class="fas fa-mobile-alt"></i> Login with OTP
</button>
<div class="signup-link">
Don't have an account? <a href="{% url 'signup' %}">Sign up here</a>
</div>
</form>
</div>
</div>
<div class="login-right">
<h2 class="features-title">Why Choose Us?</h2>
<ul class="feature-list">
<li class="feature-item">
<div class="feature-icon"><i class="fas fa-rocket"></i></div>
<div class="feature-text"><strong>Lightning Fast</strong><br>Quick and seamless login experience</div>
</li>
<li class="feature-item">
<div class="feature-icon"><i class="fas fa-shield-alt"></i></div>
<div class="feature-text"><strong>Bank-Level Security</strong><br>Your data is protected with enterprise-grade security</div>
</li>
<li class="feature-item">
<div class="feature-icon"><i class="fas fa-sync-alt"></i></div>
<div class="feature-text"><strong>Sync Across Devices</strong><br>Access your account from anywhere, anytime</div>
</li>
<li class="feature-item">
<div class="feature-icon"><i class="fas fa-headset"></i></div>
<div class="feature-text"><strong>24/7 Support</strong><br>Our team is always here to help you</div>
</li>
<li class="feature-item">
<div class="feature-icon"><i class="fas fa-chart-line"></i></div>
<div class="feature-text"><strong>Advanced Analytics</strong><br>Get insights into your business performance</div>
</li>
</ul>
</div>
</div>
</div>
<!-- Custom OTP Modal (No Bootstrap) -->
<div class="otp-modal" id="otpModal">
<div class="otp-modal-content">
<div class="otp-modal-header">
<h5 class="fw-bold">Login with OTP</h5>
<button type="button" id="closeOtpModal" style="background:none;border:none;font-size:1.5rem;cursor:pointer;">&times;</button>
</div>
<div class="otp-modal-body">
<div id="step1">
<p class="text-center text-muted mb-4">Enter your registered email or mobile number</p>
<input type="text" id="otpIdentifier" class="form-control" placeholder="Email or Phone (+91...)" required autofocus>
<button id="sendOtpBtn" class="btn-submit w-100 mt-4">
<i class="fas fa-paper-plane"></i> Send OTP
</button>
</div>
<div id="step2" style="display:none;">
<p class="text-center text-muted mb-4">Enter the 6-digit OTP sent to<br><strong id="sentTo"></strong></p>
<div class="otp-input-group">
<input type="text" class="otp-input" maxlength="1" inputmode="numeric">
<input type="text" class="otp-input" maxlength="1" inputmode="numeric">
<input type="text" class="otp-input" maxlength="1" inputmode="numeric">
<input type="text" class="otp-input" maxlength="1" inputmode="numeric">
<input type="text" class="otp-input" maxlength="1" inputmode="numeric">
<input type="text" class="otp-input" maxlength="1" inputmode="numeric">
</div>
<button id="verifyOtpBtn" class="btn-submit w-100">
<i class="fas fa-check-circle"></i> Verify & Login
</button>
<p class="text-center mt-3">
<a href="#" id="resendOtp" class="text-muted small">Resend OTP</a>
</p>
</div>
</div>
</div>
</div>
<script>
// Modal Controls
const modal = document.getElementById('otpModal');
const openBtn = document.getElementById('openOtpModal');
const closeBtn = document.getElementById('closeOtpModal');
const step1 = document.getElementById('step1');
const step2 = document.getElementById('step2');
const identifierInput = document.getElementById('otpIdentifier');
const sentTo = document.getElementById('sentTo');
const otpInputs = document.querySelectorAll('.otp-input');
openBtn.onclick = () => modal.classList.add('active');
closeBtn.onclick = () => modal.classList.remove('active');
modal.onclick = (e) => { if (e.target === modal) modal.classList.remove('active'); };
// Auto-focus OTP inputs
otpInputs.forEach((input, i) => {
input.addEventListener('input', () => {
if (input.value && i < 5) otpInputs[i + 1].focus();
});
input.addEventListener('keydown', (e) => {
if (e.key === 'Backspace' && !input.value && i > 0) otpInputs[i - 1].focus();
});
});
// Send OTP
document.getElementById('sendOtpBtn').onclick = async () => {
const identifier = identifierInput.value.trim();
if (!identifier) return alert('Please enter email or phone');
const btn = document.getElementById('sendOtpBtn');
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Sending...';
btn.disabled = true;
const res = await fetch("{% url 'request_otp' %}", {
method: 'POST',
headers: { 'X-CSRFToken': '{{ csrf_token }}' },
body: new URLSearchParams({ 'identifier': identifier })
});
if (res.ok) {
step1.style.display = 'none';
step2.style.display = 'block';
sentTo.textContent = identifier;
otpInputs[0].focus();
} else {
alert('Failed to send OTP');
}
btn.innerHTML = '<i class="fas fa-paper-plane"></i> Send OTP';
btn.disabled = false;
};
// Verify OTP
document.getElementById('verifyOtpBtn').onclick = async () => {
const otp = Array.from(otpInputs).map(i => i.value).join('');
if (otp.length !== 6) return alert('Enter full 6-digit OTP');
const btn = document.getElementById('verifyOtpBtn');
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Verifying...';
btn.disabled = true;
const res = await fetch("{% url 'verify_otp' %}", {
method: 'POST',
headers: { 'X-CSRFToken': '{{ csrf_token }}' },
body: new URLSearchParams({ 'otp': otp })
});
if (res.ok) {
window.location.href = "{% url 'home' %}";
} else {
alert('Invalid or expired OTP');
}
btn.innerHTML = '<i class="fas fa-check-circle"></i> Verify & Login';
btn.disabled = false;
};
// Resend
document.getElementById('resendOtp').onclick = (e) => {
e.preventDefault();
step2.style.display = 'none';
step1.style.display = 'block';
identifierInput.value = sentTo.textContent;
identifierInput.focus();
};
// Loading spinner on normal login
document.querySelector('form').addEventListener('submit', function() {
this.querySelector('.btn-submit').innerHTML = '<i class="fas fa-spinner fa-spin"></i> Signing In...';
});
</script>
{% endblock %}

View File

@@ -0,0 +1,31 @@
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Your OTP for {{ purpose|capfirst }}</title>
<style>
body { font-family: Arial, sans-serif; background-color: #f9f9f9; color: #333; }
.container { max-width: 600px; margin: auto; padding: 30px; background-color: #fff; border-radius: 8px; }
.otp-box { font-size: 24px; font-weight: bold; color: #2c3e50; background: #ecf0f1; padding: 15px; text-align: center; border-radius: 6px; margin: 20px 0; }
.footer { font-size: 12px; color: #999; margin-top: 30px; }
</style>
</head>
<body>
<div class="container">
<h2>Hello,</h2>
<p>You requested an OTP for <strong>{{ purpose|capfirst }}</strong>.</p>
<p>Your One-Time Password (OTP) is:</p>
<div class="otp-box">{{ otp }}</div>
<p>This OTP is valid for <strong>{{ validity_minutes }} minutes</strong>.</p>
<p><strong>⚠️ Do not share this OTP with anyone.</strong></p>
<p>If you did not request this OTP, please ignore this email or <a href="mailto:support@example.com">contact support</a> immediately.</p>
<div class="footer">
This is an automated message. Please do not reply.
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,66 @@
{% extends 'base.html' %}
{% block title %}User Profile{% endblock %}
{% load crispy_forms_tags %}
{% load static %}
{% block content %}
<!-- Profile Picture Update Modal -->
<div class="fixed inset-0 z-50 hidden overflow-y-auto bg-black bg-opacity-60" id="profilePicModal">
<div class="flex items-center justify-center min-h-screen px-4">
<div class="bg-white rounded-xl shadow-2xl w-full max-w-md">
<div class="flex justify-between items-center p-6 border-b border-gray-200">
<h3 class="text-xl font-semibold text-[#1E40AF]">Update Profile Picture</h3>
<button onclick="document.getElementById('profilePicModal').classList.add('hidden')" class="text-gray-500 hover:text-[#1E40AF] text-2xl transition-colors">&times;</button>
</div>
<div class="p-6">
<form method="POST" action="{% url 'update_profile_picture' %}" enctype="multipart/form-data">
{% csrf_token %}
{{ update_profile_photo_form|crispy }}
<button type="submit" class="mt-4 w-full bg-[#1E40AF] hover:bg-[#1E3A8A] text-white font-semibold py-2.5 px-4 rounded-lg transition-colors duration-200">Save Changes</button>
</form>
</div>
</div>
</div>
</div>
<!-- Profile Content -->
<div class="max-w-6xl mx-auto px-4 py-12">
<div class="bg-white rounded-xl shadow-xl overflow-hidden">
<div class="flex flex-col md:flex-row">
<!-- Left Sidebar -->
<div class="bg-gray-50 md:w-1/3 flex flex-col items-center justify-center p-8 text-center">
<img src="{{ user.profile_photo.url }}" alt="Profile Image" class="w-36 h-36 rounded-full object-cover mb-6 shadow-lg border-4 border-white">
<h2 class="text-2xl font-bold text-[#1E40AF]">{{ user }}</h2>
<a href="{% url 'update_profile' user.id %}" class="mt-6 w-full bg-[#1E40AF] text-white py-2.5 rounded-lg hover:bg-[#1E3A8A] font-semibold transition-colors duration-200">Update Profile</a>
<button onclick="document.getElementById('profilePicModal').classList.remove('hidden')" class="mt-3 w-full bg-[#1E40AF] text-white py-2.5 rounded-lg hover:bg-[#1E3A8A] font-semibold transition-colors duration-200">Update Profile Picture</button>
</div>
<!-- Right Content -->
<div class="md:w-2/3 p-8">
<h3 class="text-xl font-semibold text-[#1E40AF] mb-4 border-b border-gray-200 pb-3">Account Information</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
<div>
<p class="text-sm font-semibold text-gray-500">Email</p>
<p class="text-[#1E3A8A]">{{ user.email }}</p>
</div>
<div>
<p class="text-sm font-semibold text-gray-500">Phone</p>
<p class="text-[#1E3A8A]">{{ user.get_decrypted_contact_number }}</p>
</div>
</div>
<h3 class="text-xl font-semibold text-[#1E40AF] mb-4 border-b border-gray-200 pb-3">Social Media</h3>
<div class="flex space-x-6 mt-4">
<a href="#" class="text-[#1E40AF] hover:text-[#1E3A8A] text-2xl transition-colors"><i class="mdi mdi-facebook"></i></a>
<a href="#" class="text-[#1E40AF] hover:text-[#1E3A8A] text-2xl transition-colors"><i class="mdi mdi-twitter"></i></a>
<a href="#" class="text-[#1E40AF] hover:text-[#1E3A8A] text-2xl transition-colors"><i class="mdi mdi-instagram"></i></a>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,21 @@
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block title %}
Update Profile
{% endblock %}
{% block content %}
<div class="container mx-auto max-w-lg p-6 bg-white rounded-lg shadow-lg mt-10">
<h2 class="text-3xl font-bold text-center text-gray-800 mb-6">Update Profile</h2>
<form method="POST" class="space-y-6">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="w-full bg-gradient-to-r from-indigo-500 to-purple-500 hover:from-indigo-600 hover:to-purple-600 text-white font-bold py-2 px-4 rounded-lg shadow-lg transition duration-300">
Save changes
</button>
</form>
</div>
{% endblock %}

View File

@@ -0,0 +1,14 @@
{% extends 'base.html' %}
{% block title %}
Update Profile Picture
{% endblock %}
{% block content %}
<div class="container">
<h2>Update Profile Picture</h2>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">Save changes</button>
</form>
</div>
{% endblock %}

View File

@@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<title>Create User</title>
</head>
<body>
<h2>Create User</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Create</button>
</form>
<nav>
<ul>
<li><a href="{% url 'index' %}">Index</a></li>
<li><a href="{% url 'home' %}">Home</a></li>
<li><a href="{% url 'user_list' %}">User List</a></li>
</ul>
</nav>
</body>
</html>

View File

@@ -0,0 +1,316 @@
{% extends 'public_base.html' %}
{% load static %}
{% load custom_tags %}
{% block title %}Sign Up | Register your startup{% endblock %}
{% block content %}
<div class="min-h-screen flex items-center justify-center bg-gradient-to-br from-indigo-50 to-purple-50 py-8 px-4 sm:px-6 lg:px-8">
<div class="w-full max-w-6xl">
<div class="bg-white shadow-xl rounded-2xl overflow-hidden border border-gray-100">
<div class="flex flex-col lg:flex-row">
<!-- Left Side - Image Card (Hidden on mobile) -->
<div class="hidden lg:block lg:w-2/5 bg-gradient-to-br from-indigo-600 to-purple-700 p-8 lg:p-12">
<div class="flex flex-col justify-center items-center text-center text-white h-full">
<div class="max-w-sm">
<img src="{% static 'img/images or rys/Startup India Registration/hero1.png' %}" alt="Startup Registration" class="w-full h-48 lg:h-56 mb-6 lg:mb-8 rounded-lg">
<h2 class="text-2xl font-bold mb-4">Start Your Entrepreneurial Journey</h2>
<div class="space-y-4 text-left">
<div class="flex items-start">
<i class="fas fa-check-circle text-green-300 mr-3 mt-1 flex-shrink-0"></i>
<span class="text-sm">Quick and hassle-free registration process</span>
</div>
<div class="flex items-start">
<i class="fas fa-check-circle text-green-300 mr-3 mt-1 flex-shrink-0"></i>
<span class="text-sm">Expert guidance for startup compliance</span>
</div>
<div class="flex items-start">
<i class="fas fa-check-circle text-green-300 mr-3 mt-1 flex-shrink-0"></i>
<span class="text-sm">Secure and confidential data handling</span>
</div>
<div class="flex items-start">
<i class="fas fa-check-circle text-green-300 mr-3 mt-1 flex-shrink-0"></i>
<span class="text-sm">Dedicated support for your business growth</span>
</div>
</div>
</div>
</div>
</div>
<!-- Right Side - Form Card -->
<div class="w-full lg:w-3/5 py-8 lg:py-10 px-6 lg:px-8">
<!-- Mobile Header with Logo -->
<div class="lg:hidden mb-6 text-center">
<div class="flex justify-center mb-4">
<div class="w-16 h-16 bg-indigo-600 rounded-full flex items-center justify-center">
<i class="fas fa-rocket text-white text-2xl"></i>
</div>
</div>
<h2 class="text-2xl font-bold text-gray-900 mb-2">Create Your Account</h2>
<p class="text-sm text-gray-600">Join thousands of successful startups</p>
</div>
<!-- Desktop Header -->
<div class="hidden lg:block text-center mb-8">
<h2 class="text-3xl font-bold text-gray-900 mb-2">Create Your Account</h2>
<p class="text-gray-600">Start your entrepreneurial journey with us today</p>
</div>
<!-- Error Display -->
{% if form.errors %}
<div class="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-lg mb-6 animate-pulse">
<div class="flex items-center">
<i class="fa-solid fa-exclamation-circle mr-2"></i>
<strong class="font-medium">Please correct the following errors:</strong>
</div>
<ul class="list-disc list-inside mt-2 ml-2 text-sm">
{% for field, errors in form.errors.items %}
{% for error in errors %}
<li>{{ error }}</li>
{% endfor %}
{% endfor %}
</ul>
</div>
{% endif %}
<!-- Email Validation Status -->
<div id="email-status" class="flex items-center space-x-2 text-sm mb-4 hidden">
<span id="email-icon" class="text-lg"></span>
<span id="email-text"></span>
</div>
<form method="post" action="{% url 'signup' %}" class="space-y-6" novalidate>
{% csrf_token %}
<!-- Personal Information Section -->
<div class="space-y-5">
<div class="flex items-center mb-2">
<div class="w-8 h-8 bg-indigo-100 rounded-full flex items-center justify-center mr-3">
<i class="fas fa-user text-indigo-600 text-sm"></i>
</div>
<h3 class="text-lg font-semibold text-gray-900">Personal Information</h3>
</div>
<!-- Name Fields -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<!-- First Name -->
<div>
<label for="{{ form.first_name.id_for_label }}" class="block text-sm font-medium text-gray-700 mb-2">
First Name <span class="text-red-500">*</span>
</label>
<div class="relative">
<span class="absolute inset-y-0 left-0 pl-3 flex items-center text-gray-400">
<i class="fa-solid fa-user"></i>
</span>
{{ form.first_name|add_class:"appearance-none block w-full pl-10 px-3 py-3 border border-gray-300 rounded-lg shadow-sm placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 transition duration-200" }}
</div>
</div>
<!-- Last Name -->
<div>
<label for="{{ form.last_name.id_for_label }}" class="block text-sm font-medium text-gray-700 mb-2">
Last Name <span class="text-red-500">*</span>
</label>
<div class="relative">
<span class="absolute inset-y-0 left-0 pl-3 flex items-center text-gray-400">
<i class="fa-solid fa-user"></i>
</span>
{{ form.last_name|add_class:"appearance-none block w-full pl-10 px-3 py-3 border border-gray-300 rounded-lg shadow-sm placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 transition duration-200" }}
</div>
</div>
</div>
<!-- Contact & DOB Fields -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<!-- Contact Number -->
<div>
<label for="{{ form.contact_number.id_for_label }}" class="block text-sm font-medium text-gray-700 mb-2">
Contact Number
</label>
<div class="relative">
<span class="absolute inset-y-0 left-0 pl-3 flex items-center text-gray-400">
<i class="fa-solid fa-phone"></i>
</span>
{{ form.contact_number|add_class:"appearance-none block w-full pl-10 px-3 py-3 border border-gray-300 rounded-lg shadow-sm placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 transition duration-200" }}
</div>
</div>
<!-- Email Field -->
<div>
<label for="{{ form.email.id_for_label }}" class="block text-sm font-medium text-gray-700 mb-2">
Email Address <span class="text-red-500">*</span>
</label>
<div class="relative">
<span class="absolute inset-y-0 left-0 pl-3 flex items-center text-gray-400">
<i class="fa-solid fa-envelope"></i>
</span>
{{ form.email|add_class:"appearance-none block w-full pl-10 px-3 py-3 border border-gray-300 rounded-lg shadow-sm placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 transition duration-200" }}
</div>
</div>
</div>
</div>
<!-- Password Section -->
<div class="space-y-5">
<div class="flex items-center mb-2">
<div class="w-8 h-8 bg-indigo-100 rounded-full flex items-center justify-center mr-3">
<i class="fas fa-lock text-indigo-600 text-sm"></i>
</div>
<h3 class="text-lg font-semibold text-gray-900">Security</h3>
</div>
<!-- Password Field -->
<div>
<label for="{{ form.password.id_for_label }}" class="block text-sm font-medium text-gray-700 mb-2">
Password <span class="text-red-500">*</span>
</label>
<div class="relative">
<span class="absolute inset-y-0 left-0 pl-3 flex items-center text-gray-400">
<i class="fa-solid fa-lock"></i>
</span>
{{ form.password|add_class:"appearance-none block w-full pl-10 px-3 py-3 border border-gray-300 rounded-lg shadow-sm placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 transition duration-200" }}
</div>
<!-- Compact Password Requirements -->
<div class="mt-2">
<button type="button" id="password-toggle" class="flex items-center text-xs text-indigo-600 hover:text-indigo-500 transition duration-200">
<i class="fas fa-info-circle mr-1"></i>
View password requirements
</button>
<div id="password-requirements" class="hidden mt-2 p-3 bg-blue-50 border border-blue-200 rounded-lg">
<p class="text-xs font-medium text-blue-700 mb-2">Password Requirements:</p>
<ul class="text-xs text-blue-600 space-y-1">
<li class="flex items-start">
<span class="text-blue-500 mr-1"></span>
<span>Cannot be too similar to your personal information</span>
</li>
<li class="flex items-start">
<span class="text-blue-500 mr-1"></span>
<span>Must be at least 8 characters long</span>
</li>
<li class="flex items-start">
<span class="text-blue-500 mr-1"></span>
<span>Cannot be a commonly used password</span>
</li>
<li class="flex items-start">
<span class="text-blue-500 mr-1"></span>
<span>Cannot be entirely numeric</span>
</li>
</ul>
</div>
</div>
</div>
<!-- Confirm Password -->
<div>
<label for="{{ form.confirm_password.id_for_label }}" class="block text-sm font-medium text-gray-700 mb-2">
Confirm Password <span class="text-red-500">*</span>
</label>
<div class="relative">
<span class="absolute inset-y-0 left-0 pl-3 flex items-center text-gray-400">
<i class="fa-solid fa-lock"></i>
</span>
{{ form.confirm_password|add_class:"appearance-none block w-full pl-10 px-3 py-3 border border-gray-300 rounded-lg shadow-sm placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 transition duration-200" }}
</div>
</div>
</div>
<!-- Terms and Conditions -->
<div class="bg-indigo-50 p-4 rounded-lg border border-indigo-100">
<div class="flex items-start">
{{ form.terms_accepted|add_class:"h-5 w-5 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded mt-0.5" }}
<label for="{{ form.terms_accepted.id_for_label }}" class="ml-3 block text-sm text-gray-700">
<span class="font-medium text-gray-900">I accept the terms and conditions</span> <span class="text-red-500">*</span>
<p class="text-xs text-gray-500 mt-1">By creating an account, you agree to our Terms of Service and Privacy Policy.</p>
</label>
</div>
{% if form.terms_accepted.errors %}
<div class="text-red-600 text-sm mt-2 ml-8">
{{ form.terms_accepted.errors }}
</div>
{% endif %}
</div>
<!-- Submit Button -->
<div>
<button type="submit"
class="w-full flex justify-center py-3 px-4 border border-transparent text-sm font-medium rounded-lg text-white bg-gradient-to-r from-indigo-600 to-purple-600 hover:from-indigo-700 hover:to-purple-700 transition duration-200 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 shadow-lg transform hover:scale-[1.02] active:scale-[0.98]">
<i class="fa-solid fa-rocket mr-2"></i>
Launch Your Startup Journey
</button>
</div>
<!-- Login Redirect -->
<div class="text-center pt-4">
<p class="text-sm text-gray-600">
Already have an account?
<a href="{% url 'login' %}" class="font-medium text-indigo-600 hover:text-indigo-500 transition duration-200 ml-1">
Sign in here
</a>
</p>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<!-- Email AJAX Validation -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
$(document).ready(function () {
// Email validation
$('#id_email').on('blur', function () {
const username = $(this).val();
if (username) {
$.ajax({
url: '{% url "check_username" %}',
data: { 'username': username },
dataType: 'json',
success: function (data) {
$('#email-status').removeClass('hidden');
if (data.is_taken) {
$('#email-icon').html('<i class="fa-solid fa-times-circle"></i>').removeClass('text-green-600').addClass('text-red-600');
$('#email-text').text('This email is already registered.').removeClass('text-green-600').addClass('text-red-600');
$('#id_email').addClass('border-red-500 focus:border-red-500 focus:ring-red-500');
} else {
$('#email-icon').html('<i class="fa-solid fa-check-circle"></i>').removeClass('text-red-600').addClass('text-green-600');
$('#email-text').text('Email is available.').removeClass('text-red-600').addClass('text-green-600');
$('#id_email').removeClass('border-red-500 focus:border-red-500 focus:ring-red-500');
}
},
error: function() {
$('#email-status').addClass('hidden');
}
});
} else {
$('#email-status').addClass('hidden');
}
});
// Password requirements toggle
$('#password-toggle').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
$('#password-requirements').toggleClass('hidden');
if ($('#password-requirements').hasClass('hidden')) {
$(this).html('<i class="fas fa-info-circle mr-1"></i>View password requirements');
} else {
$(this).html('<i class="fas fa-times mr-1"></i>Hide password requirements');
}
});
// Hide password requirements when clicking outside
$(document).on('click', function(e) {
if (!$(e.target).closest('#password-toggle, #password-requirements').length) {
$('#password-requirements').addClass('hidden');
$('#password-toggle').html('<i class="fas fa-info-circle mr-1"></i>View password requirements');
}
});
});
</script>
{% endblock %}

View File

@@ -0,0 +1,15 @@
{% extends 'public_base.html' %}
{% block title %}
Verify
{% endblock %}
{% block content %}
<h1>You need to verify your email</h1>
<form method="post">
{% csrf_token %}
<input class="btn btn-primary max-btn" type="submit" value="Verify">
</form>
{% endblock %}

View File

@@ -0,0 +1,14 @@
{% extends 'public_base.html' %}
{% block title %}
Verify
{% endblock %}
{% block content %}
<div class="alert alert-success">
You have successfully verified your e-mail
</div>
{% endblock %}

View File

@@ -0,0 +1,18 @@
{% extends 'public_base.html' %}
{% block title %}
Verify
{% endblock %}
{% block content %}
<div class="container">
{% if messages %}
{% for message in messages %}
<div class="alert">
{{ message }}
</div>
{% endfor %}
{% endif %}
</div>
{% endblock %}

View File

@@ -0,0 +1,12 @@
{% extends 'public_base.html' %}
{% block title %}
Verify
{% endblock %}
{% block content %}
<h5>An email has been sent with instructions to verify your email</h5>
<h5>If you have not received the email. Please check the spam folder</h5>
{% endblock %}

View File

@@ -0,0 +1,20 @@
<div style="background-color: #c2c2c2; padding: 15px;">
<h2 style="margin: 0; padding: 10px; border-top-left-radius: 10px; border-top-right-radius: 10px; background-color: #fdc038; color: #ffffff;">Verify Email</h2>
<div style="margin: 0; padding: 15px; background-color: #ffffff;">
<p>Hi {{ user.name }},</p>
<p>You created an account on we-kwick, you need to verify your email. Please click on the button below to verify your email.</p>
<a href="{{ request.scheme }}://{{ domain }}{% url 'verify-email-confirm' uidb64=uid token=token %}"
style="border: 0; color: #ffffff; background-color: #fdc038; padding: 15px; font-weight: bold; text-decoration: none; border-radius: 5px; display: inline-block; margin-top: 20px;">
Verify Email
</a>
<p style="margin-top: 40px;">Or you can copy the link below to your browser</p>
<p>{{ request.scheme }}://{{ domain }}{% url 'verify-email-confirm' uidb64=uid token=token %}</p>
<p>The We-Kwick Team</p>
</div>
<div style="text-align: center; margin-top: 20px 0;">
<p>© {% now 'Y' %} <a href="">Blog</a></p>
<p>Follow us on <a href="">Twitter</a></p>
</div>
</div>

View File

@@ -0,0 +1,49 @@
{% extends 'public_base.html' %}
{% load static %}
{% block title %}Verify OTP{% endblock %}
{% block content %}
<div class="flex items-center justify-center min-h-screen bg-gray-100 px-4">
<div class="w-full max-w-md bg-white rounded-xl shadow-md p-6">
<h4 class="text-2xl font-semibold text-center text-gray-800 mb-6">Verify OTP</h4>
{% if messages %}
{% for message in messages %}
<div class="mb-4 px-4 py-3 rounded text-sm
{% if message.tags == 'error' %}
bg-red-100 text-red-700
{% elif message.tags == 'success' %}
bg-green-100 text-green-700
{% else %}
bg-blue-100 text-blue-700
{% endif %}
">
{{ message }}
</div>
{% endfor %}
{% endif %}
<form method="post" novalidate>
{% csrf_token %}
<div class="mb-4">
<label for="otpInput" class="block text-sm font-medium text-gray-700 mb-1">Enter OTP sent to your email</label>
<input type="text" name="otp" id="otpInput" maxlength="6" pattern="\d{6}"
class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="Enter 6-digit OTP" required>
</div>
<div class="mb-4">
<button type="submit"
class="w-full bg-blue-600 hover:bg-blue-700 text-white py-2 px-4 rounded-md text-lg font-medium transition">
<i class="fas fa-check-circle mr-2"></i>Verify OTP
</button>
</div>
</form>
<div class="text-center text-sm text-gray-600">
Didnt receive the OTP?
<a href="{% url 'request_otp' %}" class="text-blue-600 hover:underline">Resend</a>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,62 @@
{% extends "public_base.html" %}
{% block content %}
<div class="flex items-center justify-center min-h-screen bg-gray-100 px-4">
<div class="w-full max-w-md">
<div class="bg-white shadow-xl rounded-2xl overflow-hidden">
<!-- Header -->
<div class="px-6 py-4 border-b border-gray-200 text-center">
<h3 class="text-xl font-semibold text-gray-800">Forgot Password?</h3>
</div>
<!-- Error Messages -->
{% if form.errors %}
<div class="m-4 p-3 rounded-md bg-red-50 border border-red-200 text-red-700">
<ul class="list-disc list-inside text-sm">
{% for key, value in form.errors.items %}
<li>{{ value }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
<!-- Body -->
<div class="px-6 py-4">
<form method="POST" class="space-y-4">
{% csrf_token %}
<!-- Email Field -->
<div>
<label for="id_email" class="block text-sm font-medium text-gray-700">Email</label>
<input type="email"
name="email"
id="id_email"
class="mt-1 block w-full rounded-lg border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
placeholder="Enter email"
autocomplete="email"
maxlength="254"
required>
</div>
<!-- Submit Button -->
<div>
<button type="submit"
class="w-full py-2 px-4 bg-gray-900 text-white font-medium rounded-lg shadow hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-900">
Submit
</button>
</div>
</form>
</div>
<!-- Footer -->
<div class="px-6 py-4 border-t border-gray-200 text-center">
<a href="{% url 'login' %}" class="text-sm text-indigo-600 hover:text-indigo-800">
Back To Login
</a>
</div>
</div>
</div>
</div>
{% endblock content %}

View File

@@ -0,0 +1,9 @@
<!-- templates/registration/password_reset_complete.html -->
{% extends 'base.html' %}
{% block title %}Password reset complete{% endblock %}
{% block content %}
<h1>Password reset complete</h1>
<p>Your new password has been set. You can log in now on the <a href="{% url 'login' %}">log in page</a>.</p>
{% endblock %}

View File

@@ -0,0 +1,42 @@
{% extends "base.html" %}
{% block title %}Password Reset{% endblock %}
{% block content %}
{% load crispy_forms_tags %}
<style>
.centered-form {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(255, 255, 255, 1.0); /* Adjust the opacity as needed */
padding: 20px;
border-radius: 10px;
}
</style>
{% if validlink %}
<div class="container-fluid h-100">
<div class="row h-100">
<div class="col-sm-8">
<div class="centered-form">
<h3>Set a New Password</h3>
<form method="POST">
{% csrf_token %}
{{form|crispy}}
<button type="submit" class="btn btn-primary">Change My Password</button>
</form>
</div>
</div>
</div>
</div>
{% else %}
<p>The password reset link was invalid, possibly because it has already been used. Please request a new password reset.</p>
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,26 @@
<!-- templates/registration/password_reset_done.html -->
{% extends "base.html" %}
{% block title %}Email Sent{% endblock %}
{% block content %}
<div>
{% if messages %}
{% for message in messages %}
<div class="alert mt-2
{% if 'success' in message.tags %} alert-success
{% elif 'warning' in message.tags %} alert-warning
{% elif 'info' in message.tags %} alert-info
{% else %} alert-danger
{% endif %}">
<span class="text-danger fst-italic">{{ message }}</span>
</div>
{% endfor %}
{% endif %}
</div>
<h1>Check your inbox.</h1>
<p>We've emailed you instructions for setting your password. You should receive the email shortly!</p>
{% endblock %}

View File

@@ -0,0 +1,13 @@
{% autoescape off %}
To initiate the password reset process for your we-kwick account,
click the link below:
{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}
If clicking the link above doesn't work, please copy and paste the URL below in a new browser
window instead.
Sincerely,
we-kwick Team
{% endautoescape %}

View File

@@ -0,0 +1,24 @@
<div style="background-color: #c2c2c2; padding: 15px;">
<h2 style="margin: 0; padding: 10px; border-top-left-radius: 10px; border-top-right-radius: 10px; background-color: #fdc038; color: #ffffff;">
Password Reset
</h2>
<div style="margin: 0; padding: 15px; background-color: #ffffff;">
<p>Hi {{ user.name }},</p>
<p>
To initiate the password reset process for your we-kwick account,
click the link below:
<a href="{{ request.scheme }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}"
style="border: 0; color: #ffffff; background-color: #fdc038; padding: 15px; font-weight: bold; text-decoration: none; border-radius: 5px; display: inline-block; margin-top: 20px;">
Reset Password
</a>
<p style="margin-top: 40px;">Or you can copy the link below to your browser</p>
<p>{{ request.scheme }}://{{ domain }}{% url 'verify-email-confirm' uidb64=uid token=token %}</p>
<p>The We-Kwick Team</p>
</div>
<div style="text-align: center; margin-top: 20px 0;">
<p>© {% now 'Y' %} <a href="">Blog</a></p>
<p>Follow us on <a href="">Twitter</a></p>
</div>
</div>

View File

@@ -0,0 +1 @@
We-Kwick Password Reset

View File

@@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<title>User List</title>
</head>
<body>
<h2>User List</h2>
<ul>
{% for user in users %}
<li>
Name: {{ user.name }}, Birthday: {{ user.birthday }},
Address: {{ user.address }}, Email: {{ user.email_address }},
Contact: {{ user.contact_number }}
</li>
{% endfor %}
</ul>
<nav>
<ul>
<li><a href="{% url 'index' %}">Index</a></li>
<li><a href="{% url 'home' %}">Home</a></li>
<li><a href="{% url 'signup' %}">Create user</a></li>
</ul>
</nav>
</body>
</html>