hostbasket/actix_mvc_app/src/views/governance/create_proposal.html
Mahmoud-Emad 70ca9f1605 feat: Enhance governance dashboard with activity tracking
- Add governance activity tracker to record user actions.
- Display recent activities on the governance dashboard.
- Add a dedicated page to view all governance activities.
- Improve header information and styling across governance pages.
- Track proposal creation and voting activities.
2025-05-25 16:02:34 +03:00

229 lines
10 KiB
HTML

{% extends "base.html" %}
{% block title %}Create Proposal - Governance Dashboard{% endblock %}
{% block content %}
<div class="container-fluid">
<!-- Header -->
{% include "governance/_header.html" %}
<!-- Navigation Tabs -->
{% include "governance/_tabs.html" %}
<!-- Info Alert -->
<div class="row">
<div class="col-12">
<div class="alert alert-info alert-dismissible fade show">
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
<h5><i class="bi bi-info-circle"></i> About Creating Proposals</h5>
<p>Creating a proposal is an important step in our community governance process. Well-crafted proposals
clearly state the problem, solution, and implementation details. The community will review and vote
on your proposal, so be thorough and thoughtful in your submission.</p>
<div class="mt-2">
<a href="/governance/proposal-templates" class="btn btn-sm btn-outline-primary"><i
class="bi bi-file-earmark-text"></i> Proposal Templates</a>
</div>
</div>
</div>
</div>
<!-- Proposal Form and Guidelines in Flex Layout -->
<div class="row mb-4">
<!-- Proposal Form Column -->
<div class="col-lg-8">
<div class="card h-100">
<div class="card-header">
<h5 class="mb-0">New Proposal</h5>
</div>
<div class="card-body">
<form action="/governance/create" method="post" id="proposalForm" novalidate>
<div class="mb-3">
<label for="title" class="form-label">Title</label>
<input type="text" class="form-control" id="title" name="title" required minlength="5"
maxlength="100" placeholder="Enter a clear, concise title for your proposal">
<div class="invalid-feedback">Please provide a title (5-100 characters).</div>
<div class="form-text">Make it descriptive and specific</div>
</div>
<div class="mb-3">
<label for="description" class="form-label">Description</label>
<textarea class="form-control" id="description" name="description" rows="8" required
minlength="50" maxlength="5000"
placeholder="Provide a detailed description of your proposal..."></textarea>
<div class="invalid-feedback">Please provide a detailed description (at least 50
characters).</div>
<div class="form-text">Explain the purpose, benefits, and implementation details</div>
</div>
<div class="row mb-3">
<div class="col-md-6">
<label for="voting_start_date" class="form-label">Voting Start Date</label>
<input type="date" class="form-control" id="voting_start_date" name="voting_start_date">
<div class="invalid-feedback" id="start_date_feedback">Please select a valid start date.
</div>
<div class="form-text">When should voting begin?</div>
</div>
<div class="col-md-6">
<label for="voting_end_date" class="form-label">Voting End Date</label>
<input type="date" class="form-control" id="voting_end_date" name="voting_end_date">
<div class="invalid-feedback" id="end_date_feedback">End date must be after start date.
</div>
<div class="form-text">When should voting end?</div>
</div>
</div>
<div class="mb-3">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="draft" name="draft" value="true">
<label class="form-check-label" for="draft">
Save as draft (not ready for voting yet)
</label>
</div>
</div>
<div class="d-grid gap-2">
<button type="submit" class="btn btn-primary">Submit Proposal</button>
<a href="/governance" class="btn btn-outline-secondary">Cancel</a>
</div>
</form>
</div>
</div>
</div>
<!-- Guidelines Column -->
<div class="col-lg-4">
<div class="card bg-light h-100">
<div class="card-header">
<h5 class="mb-0">Proposal Guidelines</h5>
</div>
<div class="card-body">
<ul class="list-group list-group-flush">
<li class="list-group-item bg-transparent">
<strong>Be specific:</strong> Clearly state what you're proposing and why.
</li>
<li class="list-group-item bg-transparent">
<strong>Provide context:</strong> Explain the current situation and why change is needed.
</li>
<li class="list-group-item bg-transparent">
<strong>Consider implementation:</strong> Outline how your proposal could be implemented.
</li>
<li class="list-group-item bg-transparent">
<strong>Address concerns:</strong> Anticipate potential objections and address them.
</li>
<li class="list-group-item bg-transparent">
<strong>Be respectful:</strong> Focus on ideas, not individuals or groups.
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
{% block scripts %}
<script>
document.addEventListener('DOMContentLoaded', function () {
const form = document.getElementById('proposalForm');
const startDateInput = document.getElementById('voting_start_date');
const endDateInput = document.getElementById('voting_end_date');
const startDateFeedback = document.getElementById('start_date_feedback');
const endDateFeedback = document.getElementById('end_date_feedback');
// Set default dates
const today = new Date();
const tomorrow = new Date(today);
tomorrow.setDate(tomorrow.getDate() + 1);
const nextWeek = new Date(today);
nextWeek.setDate(nextWeek.getDate() + 7);
// Format dates for input fields
const formatDate = (date) => {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
};
// Set default values
startDateInput.value = formatDate(tomorrow);
endDateInput.value = formatDate(nextWeek);
// Validate dates when they change
function validateDates() {
const startDate = new Date(startDateInput.value);
const endDate = new Date(endDateInput.value);
const currentDate = new Date();
currentDate.setHours(0, 0, 0, 0); // Reset time to start of day
let startValid = true;
let endValid = true;
// Validate start date is not in the past
if (startDate < currentDate) {
startDateInput.classList.add('is-invalid');
startDateFeedback.textContent = 'Start date cannot be in the past.';
startValid = false;
} else {
startDateInput.classList.remove('is-invalid');
}
// Validate end date is after start date
if (endDate < startDate) {
endDateInput.classList.add('is-invalid');
endDateFeedback.textContent = 'End date must be after start date.';
endValid = false;
} else {
endDateInput.classList.remove('is-invalid');
}
return startValid && endValid;
}
// Validate on input
startDateInput.addEventListener('change', validateDates);
endDateInput.addEventListener('change', validateDates);
// Form submission validation
form.addEventListener('submit', function (event) {
let formValid = true;
// Validate required fields
const requiredFields = form.querySelectorAll('[required]');
requiredFields.forEach(field => {
if (!field.value.trim()) {
field.classList.add('is-invalid');
formValid = false;
} else {
field.classList.remove('is-invalid');
}
// Check minlength if specified
if (field.minLength && field.value.length < field.minLength) {
field.classList.add('is-invalid');
formValid = false;
}
});
// Validate dates
const datesValid = validateDates();
formValid = formValid && datesValid;
// If form is not valid, prevent submission
if (!formValid) {
event.preventDefault();
// Scroll to the first invalid element
const firstInvalid = form.querySelector('.is-invalid');
if (firstInvalid) {
firstInvalid.scrollIntoView({ behavior: 'smooth', block: 'center' });
firstInvalid.focus();
}
}
});
// Initial validation
validateDates();
});
</script>
{% endblock %}
{% endblock %}