733 lines
38 KiB
HTML
733 lines
38 KiB
HTML
{% extends "base.html" %}
|
|
{% load static %}
|
|
|
|
{% block title %}
|
|
{% if form.instance.id %}Edit{% else %}Create{% endif %} Performance Review | HR Management
|
|
{% endblock %}
|
|
|
|
{% block css %}
|
|
<!-- Select2 CSS -->
|
|
<link href="{% static 'plugins/select2/dist/css/select2.min.css' %}" rel="stylesheet" />
|
|
<!-- DateRangePicker CSS -->
|
|
<link href="{% static 'plugins/bootstrap-daterangepicker/daterangepicker.css' %}" rel="stylesheet" />
|
|
<!-- Summernote CSS -->
|
|
<link href="{% static 'plugins/summernote/dist/summernote-lite.css' %}" rel="stylesheet" />
|
|
<style>
|
|
.form-section {
|
|
background-color: #f8f9fa;
|
|
border-radius: 5px;
|
|
padding: 20px;
|
|
margin-bottom: 20px;
|
|
}
|
|
.form-section-title {
|
|
border-bottom: 1px solid #dee2e6;
|
|
padding-bottom: 10px;
|
|
margin-bottom: 20px;
|
|
}
|
|
.category-card {
|
|
border: 1px solid #dee2e6;
|
|
border-radius: 5px;
|
|
padding: 15px;
|
|
margin-bottom: 15px;
|
|
}
|
|
.rating-stars {
|
|
color: #ffc107;
|
|
font-size: 24px;
|
|
cursor: pointer;
|
|
}
|
|
.rating-stars .fas, .rating-stars .far {
|
|
margin-right: 5px;
|
|
}
|
|
.goal-row {
|
|
background-color: #f8f9fa;
|
|
border-radius: 5px;
|
|
padding: 15px;
|
|
margin-bottom: 10px;
|
|
}
|
|
.remove-goal {
|
|
color: #dc3545;
|
|
cursor: pointer;
|
|
}
|
|
.help-sidebar {
|
|
position: sticky;
|
|
top: 20px;
|
|
}
|
|
.help-card {
|
|
border-left: 4px solid #2d62ed;
|
|
}
|
|
.select2-container--default .select2-selection--single {
|
|
height: 38px;
|
|
border: 1px solid #ced4da;
|
|
}
|
|
.select2-container--default .select2-selection--single .select2-selection__rendered {
|
|
line-height: 38px;
|
|
}
|
|
.select2-container--default .select2-selection--single .select2-selection__arrow {
|
|
height: 36px;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<!-- begin breadcrumb -->
|
|
<ol class="breadcrumb float-xl-end">
|
|
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">Home</a></li>
|
|
<li class="breadcrumb-item"><a href="{% url 'hr:dashboard' %}">HR</a></li>
|
|
<li class="breadcrumb-item"><a href="{% url 'hr:performance_review_list' %}">Performance Reviews</a></li>
|
|
<li class="breadcrumb-item active">
|
|
{% if form.instance.id %}Edit{% else %}Create{% endif %} Review
|
|
</li>
|
|
</ol>
|
|
<!-- end breadcrumb -->
|
|
|
|
<!-- begin page-header -->
|
|
<h1 class="page-header">
|
|
{% if form.instance.id %}Edit{% else %}Create{% endif %} Performance Review
|
|
</h1>
|
|
<!-- end page-header -->
|
|
|
|
<!-- begin row -->
|
|
<div class="row">
|
|
<!-- begin col-9 -->
|
|
<div class="col-xl-9">
|
|
<!-- begin panel -->
|
|
<div class="panel panel-inverse">
|
|
<!-- begin panel-heading -->
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">
|
|
{% if form.instance.id %}Edit{% else %}Create{% endif %} Performance Review
|
|
</h4>
|
|
<div class="panel-heading-btn">
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-success" data-toggle="panel-reload"><i class="fa fa-redo"></i></a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-warning" data-toggle="panel-collapse"><i class="fa fa-minus"></i></a>
|
|
</div>
|
|
</div>
|
|
<!-- end panel-heading -->
|
|
|
|
<!-- begin panel-body -->
|
|
<div class="panel-body">
|
|
<!-- Form Errors -->
|
|
{% if form.errors %}
|
|
<div class="alert alert-danger">
|
|
<h5><i class="fas fa-exclamation-circle"></i> Please correct the errors below:</h5>
|
|
<ul class="mb-0">
|
|
{% for field in form %}
|
|
{% for error in field.errors %}
|
|
<li>{{ field.label }}: {{ error }}</li>
|
|
{% endfor %}
|
|
{% endfor %}
|
|
{% for error in form.non_field_errors %}
|
|
<li>{{ error }}</li>
|
|
{% endfor %}
|
|
</ul>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<form method="post" id="reviewForm" enctype="multipart/form-data">
|
|
{% csrf_token %}
|
|
|
|
<!-- Basic Information Section -->
|
|
<div class="form-section">
|
|
<h5 class="form-section-title">Basic Information</h5>
|
|
<div class="row">
|
|
<div class="col-md-6 mb-3">
|
|
<label for="{{ form.employee.id_for_label }}" class="form-label">Employee <span class="text-danger">*</span></label>
|
|
{{ form.employee }}
|
|
{% if form.employee.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.employee.errors }}</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<label for="{{ form.reviewer.id_for_label }}" class="form-label">Reviewer <span class="text-danger">*</span></label>
|
|
{{ form.reviewer }}
|
|
{% if form.reviewer.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.reviewer.errors }}</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<label for="{{ form.review_type.id_for_label }}" class="form-label">Review Type <span class="text-danger">*</span></label>
|
|
{{ form.review_type }}
|
|
{% if form.review_type.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.review_type.errors }}</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<label for="{{ form.status.id_for_label }}" class="form-label">Status <span class="text-danger">*</span></label>
|
|
{{ form.status }}
|
|
{% if form.status.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.status.errors }}</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<label for="review_period" class="form-label">Review Period <span class="text-danger">*</span></label>
|
|
<input type="text" class="form-control" id="review_period" name="review_period">
|
|
<input type="hidden" id="{{ form.period_start.id_for_label }}" name="{{ form.period_start.html_name }}" value="{{ form.period_start.value|date:'Y-m-d'|default:'' }}">
|
|
<input type="hidden" id="{{ form.period_end.id_for_label }}" name="{{ form.period_end.html_name }}" value="{{ form.period_end.value|date:'Y-m-d'|default:'' }}">
|
|
{% if form.period_start.errors or form.period_end.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.period_start.errors }}
|
|
{{ form.period_end.errors }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<label for="{{ form.due_date.id_for_label }}" class="form-label">Due Date <span class="text-danger">*</span></label>
|
|
{{ form.due_date }}
|
|
{% if form.due_date.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.due_date.errors }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Performance Categories Section -->
|
|
<div class="form-section">
|
|
<h5 class="form-section-title">Performance Categories</h5>
|
|
<div id="categories-container">
|
|
<!-- Categories will be added here dynamically -->
|
|
{% if categories %}
|
|
{% for category in categories %}
|
|
<div class="category-card" data-category-id="{{ category.id }}">
|
|
<div class="row">
|
|
<div class="col-md-12 mb-3">
|
|
<label class="form-label">Category Name <span class="text-danger">*</span></label>
|
|
<input type="text" class="form-control category-name" name="category_name[]" value="{{ category.name }}" required>
|
|
<input type="hidden" class="category-id" name="category_id[]" value="{{ category.id }}">
|
|
</div>
|
|
<div class="col-md-12 mb-3">
|
|
<label class="form-label">Rating <span class="text-danger">*</span></label>
|
|
<div class="rating-stars" data-rating="{{ category.score }}">
|
|
<i class="far fa-star" data-value="1"></i>
|
|
<i class="far fa-star" data-value="2"></i>
|
|
<i class="far fa-star" data-value="3"></i>
|
|
<i class="far fa-star" data-value="4"></i>
|
|
<i class="far fa-star" data-value="5"></i>
|
|
</div>
|
|
<input type="hidden" class="category-score" name="category_score[]" value="{{ category.score }}">
|
|
</div>
|
|
<div class="col-md-12 mb-3">
|
|
<label class="form-label">Comments</label>
|
|
<textarea class="form-control category-comments" name="category_comments[]" rows="3">{{ category.comments }}</textarea>
|
|
</div>
|
|
<div class="col-md-12 text-end">
|
|
<button type="button" class="btn btn-sm btn-danger remove-category">
|
|
<i class="fas fa-trash"></i> Remove Category
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
{% endif %}
|
|
</div>
|
|
<div class="text-center mt-3">
|
|
<button type="button" class="btn btn-success" id="add-category">
|
|
<i class="fas fa-plus"></i> Add Category
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Goals and Achievements Section -->
|
|
<div class="form-section">
|
|
<h5 class="form-section-title">Goals and Achievements</h5>
|
|
<div id="goals-container">
|
|
<!-- Goals will be added here dynamically -->
|
|
{% if goals %}
|
|
{% for goal in goals %}
|
|
<div class="goal-row" data-goal-id="{{ goal.id }}">
|
|
<div class="row">
|
|
<div class="col-md-12 mb-3">
|
|
<label class="form-label">Goal Description <span class="text-danger">*</span></label>
|
|
<input type="text" class="form-control goal-description" name="goal_description[]" value="{{ goal.description }}" required>
|
|
<input type="hidden" class="goal-id" name="goal_id[]" value="{{ goal.id }}">
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<label class="form-label">Target <span class="text-danger">*</span></label>
|
|
<input type="text" class="form-control goal-target" name="goal_target[]" value="{{ goal.target }}" required>
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<label class="form-label">Achievement</label>
|
|
<input type="text" class="form-control goal-achievement" name="goal_achievement[]" value="{{ goal.achievement }}">
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<label class="form-label">Status <span class="text-danger">*</span></label>
|
|
<select class="form-select goal-status" name="goal_status[]" required>
|
|
<option value="IN_PROGRESS" {% if goal.status == 'IN_PROGRESS' %}selected{% endif %}>In Progress</option>
|
|
<option value="EXCEEDED" {% if goal.status == 'EXCEEDED' %}selected{% endif %}>Exceeded</option>
|
|
<option value="ACHIEVED" {% if goal.status == 'ACHIEVED' %}selected{% endif %}>Achieved</option>
|
|
<option value="PARTIALLY_ACHIEVED" {% if goal.status == 'PARTIALLY_ACHIEVED' %}selected{% endif %}>Partially Achieved</option>
|
|
<option value="NOT_ACHIEVED" {% if goal.status == 'NOT_ACHIEVED' %}selected{% endif %}>Not Achieved</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-6 mb-3 text-end">
|
|
<label class="form-label"> </label>
|
|
<div>
|
|
<button type="button" class="btn btn-sm btn-danger remove-goal">
|
|
<i class="fas fa-trash"></i> Remove Goal
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
{% endif %}
|
|
</div>
|
|
<div class="text-center mt-3">
|
|
<button type="button" class="btn btn-success" id="add-goal">
|
|
<i class="fas fa-plus"></i> Add Goal
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Strengths and Areas for Improvement Section -->
|
|
<div class="form-section">
|
|
<h5 class="form-section-title">Strengths and Areas for Improvement</h5>
|
|
<div class="row">
|
|
<div class="col-md-6 mb-3">
|
|
<label for="{{ form.strengths.id_for_label }}" class="form-label">Strengths</label>
|
|
<p class="form-text">Enter one strength per line</p>
|
|
{{ form.strengths }}
|
|
{% if form.strengths.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.strengths.errors }}</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<label for="{{ form.areas_for_improvement.id_for_label }}" class="form-label">Areas for Improvement</label>
|
|
<p class="form-text">Enter one area per line</p>
|
|
{{ form.areas_for_improvement }}
|
|
{% if form.areas_for_improvement.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.areas_for_improvement.errors }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Development Plan Section -->
|
|
<div class="form-section">
|
|
<h5 class="form-section-title">Development Plan</h5>
|
|
<div class="row">
|
|
<div class="col-md-12 mb-3">
|
|
<label for="{{ form.development_plan.id_for_label }}" class="form-label">Development Plan</label>
|
|
{{ form.development_plan }}
|
|
{% if form.development_plan.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.development_plan.errors }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Comments Section -->
|
|
<div class="form-section">
|
|
<h5 class="form-section-title">Comments</h5>
|
|
<div class="row">
|
|
<div class="col-md-6 mb-3">
|
|
<label for="{{ form.reviewer_comments.id_for_label }}" class="form-label">Reviewer Comments</label>
|
|
{{ form.reviewer_comments }}
|
|
{% if form.reviewer_comments.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.reviewer_comments.errors }}</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<label for="{{ form.employee_comments.id_for_label }}" class="form-label">Employee Comments</label>
|
|
{{ form.employee_comments }}
|
|
{% if form.employee_comments.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.employee_comments.errors }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Overall Score Section -->
|
|
<div class="form-section">
|
|
<h5 class="form-section-title">Overall Score</h5>
|
|
<div class="row">
|
|
<div class="col-md-6 mb-3">
|
|
<label for="{{ form.overall_score.id_for_label }}" class="form-label">Overall Score</label>
|
|
<div class="input-group">
|
|
{{ form.overall_score }}
|
|
<span class="input-group-text">/5</span>
|
|
</div>
|
|
<div class="form-text">Leave blank to calculate automatically from categories</div>
|
|
{% if form.overall_score.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.overall_score.errors }}</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<label for="{{ form.completion_percentage.id_for_label }}" class="form-label">Completion Percentage</label>
|
|
<div class="input-group">
|
|
{{ form.completion_percentage }}
|
|
<span class="input-group-text">%</span>
|
|
</div>
|
|
<div class="form-text">Only applicable for In Progress reviews</div>
|
|
{% if form.completion_percentage.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.completion_percentage.errors }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Attachments Section -->
|
|
<div class="form-section">
|
|
<h5 class="form-section-title">Attachments</h5>
|
|
<div class="row">
|
|
<div class="col-md-12 mb-3">
|
|
<label for="{{ form.attachments.id_for_label }}" class="form-label">Attachments</label>
|
|
{{ form.attachments }}
|
|
<div class="form-text">You can upload multiple files (PDF, Word, Excel, etc.)</div>
|
|
{% if form.attachments.errors %}
|
|
<div class="invalid-feedback d-block">{{ form.attachments.errors }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
{% if existing_attachments %}
|
|
<div class="mt-3">
|
|
<h6>Existing Attachments</h6>
|
|
<div class="list-group">
|
|
{% for attachment in existing_attachments %}
|
|
<div class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
|
|
<div>
|
|
<i class="fas fa-file me-2"></i>
|
|
<a href="{{ attachment.file.url }}" target="_blank">{{ attachment.title }}</a>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="delete_attachment_{{ attachment.id }}" id="delete_attachment_{{ attachment.id }}">
|
|
<label class="form-check-label" for="delete_attachment_{{ attachment.id }}">
|
|
Delete
|
|
</label>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<!-- Form Actions -->
|
|
<div class="d-flex justify-content-between">
|
|
<a href="{% url 'hr:performance_review_list' %}" class="btn btn-secondary">
|
|
<i class="fas fa-times"></i> Cancel
|
|
</a>
|
|
<div>
|
|
<button type="submit" name="save_draft" class="btn btn-info">
|
|
<i class="fas fa-save"></i> Save as Draft
|
|
</button>
|
|
<button type="submit" name="save" class="btn btn-primary">
|
|
<i class="fas fa-check"></i> Save Review
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<!-- end panel-body -->
|
|
</div>
|
|
<!-- end panel -->
|
|
</div>
|
|
<!-- end col-9 -->
|
|
|
|
<!-- begin col-3 -->
|
|
<div class="col-xl-3">
|
|
<div class="help-sidebar">
|
|
<!-- Help Card -->
|
|
<div class="card help-card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">Help & Guidelines</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<h6>Performance Review Process</h6>
|
|
<p>Follow these steps to complete a performance review:</p>
|
|
<ol>
|
|
<li>Fill in the basic information</li>
|
|
<li>Add performance categories and ratings</li>
|
|
<li>Document goals and achievements</li>
|
|
<li>Identify strengths and areas for improvement</li>
|
|
<li>Create a development plan</li>
|
|
<li>Add comments from both reviewer and employee</li>
|
|
</ol>
|
|
|
|
<h6>Rating Scale</h6>
|
|
<ul class="list-unstyled">
|
|
<li><i class="fas fa-star text-warning"></i><i class="fas fa-star text-warning"></i><i class="fas fa-star text-warning"></i><i class="fas fa-star text-warning"></i><i class="fas fa-star text-warning"></i> (5) - Excellent</li>
|
|
<li><i class="fas fa-star text-warning"></i><i class="fas fa-star text-warning"></i><i class="fas fa-star text-warning"></i><i class="fas fa-star text-warning"></i><i class="far fa-star text-warning"></i> (4) - Good</li>
|
|
<li><i class="fas fa-star text-warning"></i><i class="fas fa-star text-warning"></i><i class="fas fa-star text-warning"></i><i class="far fa-star text-warning"></i><i class="far fa-star text-warning"></i> (3) - Average</li>
|
|
<li><i class="fas fa-star text-warning"></i><i class="fas fa-star text-warning"></i><i class="far fa-star text-warning"></i><i class="far fa-star text-warning"></i><i class="far fa-star text-warning"></i> (2) - Needs Improvement</li>
|
|
<li><i class="fas fa-star text-warning"></i><i class="far fa-star text-warning"></i><i class="far fa-star text-warning"></i><i class="far fa-star text-warning"></i><i class="far fa-star text-warning"></i> (1) - Poor</li>
|
|
</ul>
|
|
|
|
<h6>Tips for Effective Reviews</h6>
|
|
<ul>
|
|
<li>Be specific and provide examples</li>
|
|
<li>Focus on behaviors, not personality</li>
|
|
<li>Balance positive feedback with areas for improvement</li>
|
|
<li>Set clear, measurable goals</li>
|
|
<li>Create actionable development plans</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Status Card -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">Review Status</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<p>The review status determines the workflow:</p>
|
|
<ul>
|
|
<li><strong>Draft</strong> - Initial creation, not visible to employee</li>
|
|
<li><strong>In Progress</strong> - Review is being conducted</li>
|
|
<li><strong>Completed</strong> - Review is finalized and locked</li>
|
|
<li><strong>Overdue</strong> - Past due date, requires attention</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- end col-3 -->
|
|
</div>
|
|
<!-- end row -->
|
|
{% endblock %}
|
|
|
|
{% block js %}
|
|
<!-- Select2 JS -->
|
|
<script src="{% static 'plugins/select2/dist/js/select2.min.js' %}"></script>
|
|
<!-- DateRangePicker JS -->
|
|
<script src="{% static 'plugins/moment/min/moment.min.js' %}"></script>
|
|
<script src="{% static 'plugins/bootstrap-daterangepicker/daterangepicker.js' %}"></script>
|
|
<!-- Summernote JS -->
|
|
<script src="{% static 'plugins/summernote/dist/summernote-lite.min.js' %}"></script>
|
|
|
|
<script>
|
|
$(document).ready(function() {
|
|
// Initialize Select2
|
|
$('#{{ form.employee.id_for_label }}, #{{ form.reviewer.id_for_label }}, #{{ form.review_type.id_for_label }}, #{{ form.status.id_for_label }}').select2({
|
|
placeholder: "Select an option",
|
|
allowClear: true,
|
|
width: '100%'
|
|
});
|
|
|
|
// Initialize DateRangePicker for review period
|
|
$('#review_period').daterangepicker({
|
|
opens: 'left',
|
|
autoUpdateInput: false,
|
|
locale: {
|
|
cancelLabel: 'Clear',
|
|
format: 'YYYY-MM-DD'
|
|
}
|
|
});
|
|
|
|
// Set initial value for review period if exists
|
|
var startDate = $('#{{ form.period_start.id_for_label }}').val();
|
|
var endDate = $('#{{ form.period_end.id_for_label }}').val();
|
|
if (startDate && endDate) {
|
|
$('#review_period').val(moment(startDate).format('YYYY-MM-DD') + ' - ' + moment(endDate).format('YYYY-MM-DD'));
|
|
}
|
|
|
|
// Handle date range picker apply event
|
|
$('#review_period').on('apply.daterangepicker', function(ev, picker) {
|
|
$(this).val(picker.startDate.format('YYYY-MM-DD') + ' - ' + picker.endDate.format('YYYY-MM-DD'));
|
|
$('#{{ form.period_start.id_for_label }}').val(picker.startDate.format('YYYY-MM-DD'));
|
|
$('#{{ form.period_end.id_for_label }}').val(picker.endDate.format('YYYY-MM-DD'));
|
|
});
|
|
|
|
// Handle date range picker cancel event
|
|
$('#review_period').on('cancel.daterangepicker', function(ev, picker) {
|
|
$(this).val('');
|
|
$('#{{ form.period_start.id_for_label }}').val('');
|
|
$('#{{ form.period_end.id_for_label }}').val('');
|
|
});
|
|
|
|
// Initialize DatePicker for due date
|
|
$('#{{ form.due_date.id_for_label }}').daterangepicker({
|
|
singleDatePicker: true,
|
|
showDropdowns: true,
|
|
autoUpdateInput: false,
|
|
locale: {
|
|
format: 'YYYY-MM-DD'
|
|
}
|
|
});
|
|
|
|
// Set initial value for due date if exists
|
|
var dueDate = $('#{{ form.due_date.id_for_label }}').val();
|
|
if (dueDate) {
|
|
$('#{{ form.due_date.id_for_label }}').val(moment(dueDate).format('YYYY-MM-DD'));
|
|
}
|
|
|
|
// Handle due date picker apply event
|
|
$('#{{ form.due_date.id_for_label }}').on('apply.daterangepicker', function(ev, picker) {
|
|
$(this).val(picker.startDate.format('YYYY-MM-DD'));
|
|
});
|
|
|
|
// Initialize Summernote for rich text editors
|
|
$('#{{ form.development_plan.id_for_label }}, #{{ form.reviewer_comments.id_for_label }}, #{{ form.employee_comments.id_for_label }}').summernote({
|
|
height: 150,
|
|
toolbar: [
|
|
['style', ['style']],
|
|
['font', ['bold', 'underline', 'clear']],
|
|
['para', ['ul', 'ol', 'paragraph']],
|
|
['insert', ['link']],
|
|
['view', ['fullscreen', 'codeview', 'help']]
|
|
]
|
|
});
|
|
|
|
// Handle star ratings
|
|
$('.rating-stars').each(function() {
|
|
var $stars = $(this);
|
|
var rating = $stars.data('rating');
|
|
|
|
// Set initial rating
|
|
if (rating) {
|
|
$stars.find('.far.fa-star').each(function() {
|
|
if ($(this).data('value') <= rating) {
|
|
$(this).removeClass('far').addClass('fas');
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
$(document).on('click', '.rating-stars .fa-star', function() {
|
|
var $star = $(this);
|
|
var $stars = $star.parent();
|
|
var value = $star.data('value');
|
|
|
|
// Update hidden input
|
|
$stars.siblings('.category-score').val(value);
|
|
|
|
// Update stars
|
|
$stars.find('.fa-star').each(function() {
|
|
if ($(this).data('value') <= value) {
|
|
$(this).removeClass('far').addClass('fas');
|
|
} else {
|
|
$(this).removeClass('fas').addClass('far');
|
|
}
|
|
});
|
|
});
|
|
|
|
// Add new category
|
|
$('#add-category').click(function() {
|
|
var categoryId = 'new_' + new Date().getTime();
|
|
var categoryHtml = `
|
|
<div class="category-card" data-category-id="${categoryId}">
|
|
<div class="row">
|
|
<div class="col-md-12 mb-3">
|
|
<label class="form-label">Category Name <span class="text-danger">*</span></label>
|
|
<input type="text" class="form-control category-name" name="category_name[]" required>
|
|
<input type="hidden" class="category-id" name="category_id[]" value="${categoryId}">
|
|
</div>
|
|
<div class="col-md-12 mb-3">
|
|
<label class="form-label">Rating <span class="text-danger">*</span></label>
|
|
<div class="rating-stars" data-rating="0">
|
|
<i class="far fa-star" data-value="1"></i>
|
|
<i class="far fa-star" data-value="2"></i>
|
|
<i class="far fa-star" data-value="3"></i>
|
|
<i class="far fa-star" data-value="4"></i>
|
|
<i class="far fa-star" data-value="5"></i>
|
|
</div>
|
|
<input type="hidden" class="category-score" name="category_score[]" value="0">
|
|
</div>
|
|
<div class="col-md-12 mb-3">
|
|
<label class="form-label">Comments</label>
|
|
<textarea class="form-control category-comments" name="category_comments[]" rows="3"></textarea>
|
|
</div>
|
|
<div class="col-md-12 text-end">
|
|
<button type="button" class="btn btn-sm btn-danger remove-category">
|
|
<i class="fas fa-trash"></i> Remove Category
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
$('#categories-container').append(categoryHtml);
|
|
});
|
|
|
|
// Remove category
|
|
$(document).on('click', '.remove-category', function() {
|
|
$(this).closest('.category-card').remove();
|
|
});
|
|
|
|
// Add new goal
|
|
$('#add-goal').click(function() {
|
|
var goalId = 'new_' + new Date().getTime();
|
|
var goalHtml = `
|
|
<div class="goal-row" data-goal-id="${goalId}">
|
|
<div class="row">
|
|
<div class="col-md-12 mb-3">
|
|
<label class="form-label">Goal Description <span class="text-danger">*</span></label>
|
|
<input type="text" class="form-control goal-description" name="goal_description[]" required>
|
|
<input type="hidden" class="goal-id" name="goal_id[]" value="${goalId}">
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<label class="form-label">Target <span class="text-danger">*</span></label>
|
|
<input type="text" class="form-control goal-target" name="goal_target[]" required>
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<label class="form-label">Achievement</label>
|
|
<input type="text" class="form-control goal-achievement" name="goal_achievement[]">
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<label class="form-label">Status <span class="text-danger">*</span></label>
|
|
<select class="form-select goal-status" name="goal_status[]" required>
|
|
<option value="IN_PROGRESS">In Progress</option>
|
|
<option value="EXCEEDED">Exceeded</option>
|
|
<option value="ACHIEVED">Achieved</option>
|
|
<option value="PARTIALLY_ACHIEVED">Partially Achieved</option>
|
|
<option value="NOT_ACHIEVED">Not Achieved</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-6 mb-3 text-end">
|
|
<label class="form-label"> </label>
|
|
<div>
|
|
<button type="button" class="btn btn-sm btn-danger remove-goal">
|
|
<i class="fas fa-trash"></i> Remove Goal
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
$('#goals-container').append(goalHtml);
|
|
});
|
|
|
|
// Remove goal
|
|
$(document).on('click', '.remove-goal', function() {
|
|
$(this).closest('.goal-row').remove();
|
|
});
|
|
|
|
// Form validation
|
|
$('#reviewForm').submit(function(e) {
|
|
var isValid = true;
|
|
|
|
// Check if at least one category exists
|
|
if ($('#categories-container .category-card').length === 0) {
|
|
alert('Please add at least one performance category.');
|
|
isValid = false;
|
|
}
|
|
|
|
// Check if all categories have names and ratings
|
|
$('#categories-container .category-card').each(function() {
|
|
var categoryName = $(this).find('.category-name').val();
|
|
var categoryScore = $(this).find('.category-score').val();
|
|
|
|
if (!categoryName || categoryName.trim() === '') {
|
|
alert('Please enter a name for all categories.');
|
|
isValid = false;
|
|
return false;
|
|
}
|
|
|
|
if (!categoryScore || categoryScore === '0') {
|
|
alert('Please rate all categories.');
|
|
isValid = false;
|
|
return false;
|
|
}
|
|
});
|
|
|
|
if (!isValid) {
|
|
e.preventDefault();
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
{% endblock %}
|
|
|