Merge pull request 'Village Add, Edit and Delete Messages done' (#12) from swapnil-dev into main

Reviewed-on: #12
This commit was merged in pull request #12.
This commit is contained in:
2026-03-24 09:47:16 +00:00
4 changed files with 298 additions and 278 deletions

View File

@@ -83,17 +83,29 @@ def check_village():
return village.CheckVillage(request=request) return village.CheckVillage(request=request)
# ------------------------- Delete Village -------------------------
@village_bp.route('/delete_village/<int:village_id>') @village_bp.route('/delete_village/<int:village_id>')
@login_required @login_required
def delete_village(village_id): def delete_village(village_id):
village = Village() village = Village()
village.DeleteVillage(request=request, village_id=village_id) village.DeleteVillage(request=request, village_id=village_id)
flash(village.resultMessage, "success" if village.isSuccess else "error") # ✅ Convert resultMessage to string if it's a Response or tuple
return redirect(url_for('village.add_village')) raw_msg = village.resultMessage
if isinstance(raw_msg, tuple):
# e.g., (<Response ...>, 200)
msg = "Village deleted successfully!"
elif hasattr(raw_msg, 'get_data'):
# Flask Response object
msg = raw_msg.get_data(as_text=True) # get raw text
else:
# fallback
msg = str(raw_msg) if raw_msg else "Village deleted successfully!"
return jsonify({
"status": "success" if village.isSuccess else "error",
"message": msg
})
# ------------------------- Edit Village ------------------------- # ------------------------- Edit Village -------------------------
@village_bp.route('/edit_village/<int:village_id>', methods=['GET', 'POST']) @village_bp.route('/edit_village/<int:village_id>', methods=['GET', 'POST'])

View File

@@ -1,41 +1,37 @@
window.onload = function () { window.onload = function () {
if (document.getElementById('Village_Name')) {
document.getElementById('Village_Name').focus(); document.getElementById('Village_Name').focus();
}
}; };
$(document).ready(function () { $(document).ready(function () {
// 🔥 RESTORE VIEW MODE AFTER RELOAD // RUN ONLY IF THIS PAGE HAS FORM/TABLE
var viewMode = localStorage.getItem("viewMode"); if ($('#addForm').length && $('#addTable').length) {
if (viewMode === "table") { // ✅ DEFAULT VIEW → SHOW FORM
$('#addForm').hide();
$('#addTable').show();
} else {
$('#addForm').show(); $('#addForm').show();
$('#addTable').hide(); $('#addTable').hide();
}
// 🔥 BUTTON TOGGLE LOGIC // 🔥 BUTTON TOGGLE
$('#addButton').click(function () { $('#addButton').click(function () {
$('#addForm').show(); $('#addForm').show();
$('#addTable').hide(); $('#addTable').hide();
localStorage.setItem("viewMode", "form");
}); });
$('#displayButton').click(function () { $('#displayButton').click(function () {
$('#addForm').hide(); $('#addForm').hide();
$('#addTable').show(); $('#addTable').show();
localStorage.setItem("viewMode", "table");
}); });
}
// ===============================
// STATE → DISTRICT // STATE → DISTRICT
// ===============================
if ($('#state_Id').length) {
$('#state_Id').change(function () { $('#state_Id').change(function () {
var stateId = $(this).val(); var stateId = $(this).val();
@@ -54,25 +50,24 @@ $(document).ready(function () {
districtDropdown.append('<option value="" disabled selected>Select District</option>'); districtDropdown.append('<option value="" disabled selected>Select District</option>');
data.forEach(function (district) { data.forEach(function (district) {
districtDropdown.append( districtDropdown.append(
'<option value="' + district.id + '">' + district.name + '</option>' '<option value="' + district.id + '">' + district.name + '</option>'
); );
}); });
districtDropdown.prop('disabled', false); districtDropdown.prop('disabled', false);
}
});
}
});
} }
});
}
});
// ===============================
// DISTRICT → BLOCK // DISTRICT → BLOCK
// ===============================
if ($('#district_Id').length) {
$('#district_Id').change(function () { $('#district_Id').change(function () {
var districtId = $(this).val(); var districtId = $(this).val();
@@ -91,25 +86,24 @@ $(document).ready(function () {
blockDropdown.append('<option value="" disabled selected>Select Block</option>'); blockDropdown.append('<option value="" disabled selected>Select Block</option>');
data.forEach(function (block) { data.forEach(function (block) {
blockDropdown.append( blockDropdown.append(
'<option value="' + block.id + '">' + block.name + '</option>' '<option value="' + block.id + '">' + block.name + '</option>'
); );
}); });
blockDropdown.prop('disabled', false); blockDropdown.prop('disabled', false);
}
});
}
});
} }
});
}
});
// ===============================
// VILLAGE NAME VALIDATION // VILLAGE NAME VALIDATION
// ===============================
if ($('#Village_Name').length) {
$('#Village_Name').on('input', function () { $('#Village_Name').on('input', function () {
var villageName = $(this).val(); var villageName = $(this).val();
@@ -127,13 +121,16 @@ $(document).ready(function () {
$('#villageMessage').text(''); $('#villageMessage').text('');
$('#submitVillage').prop('disabled', false); $('#submitVillage').prop('disabled', false);
}
});
} }
});
// ===============================
// CHECK DUPLICATE VILLAGE // CHECK DUPLICATE VILLAGE
// ===============================
if ($('#Village_Name').length && $('#block_Id').length) {
$('#Village_Name, #block_Id').on('change keyup', function () { $('#Village_Name, #block_Id').on('change keyup', function () {
var blockId = $('#block_Id').val(); var blockId = $('#block_Id').val();
@@ -142,7 +139,6 @@ $(document).ready(function () {
if (blockId && villageName) { if (blockId && villageName) {
$.ajax({ $.ajax({
url: '/check_village', url: '/check_village',
type: 'POST', type: 'POST',
@@ -168,9 +164,7 @@ $(document).ready(function () {
.css('color', 'green'); .css('color', 'green');
$('#submitVillage').prop('disabled', false); $('#submitVillage').prop('disabled', false);
} }
}, },
error: function () { error: function () {
@@ -180,85 +174,77 @@ $(document).ready(function () {
.css('color', 'red'); .css('color', 'red');
$('#submitVillage').prop('disabled', true); $('#submitVillage').prop('disabled', true);
}
});
}
});
} }
});
} // ===============================
// ADD VILLAGE (SAFE SCOPE FIX)
// ===============================
if ($('#villageForm').length) {
});
// ADD VILLAGE
$('#villageForm').submit(function (event) { $('#villageForm').submit(function (event) {
event.preventDefault(); event.preventDefault();
$.ajax({ $.ajax({
url: '/add_village', url: '/add_village',
type: 'POST', type: 'POST',
data: $(this).serialize(), data: $(this).serialize(),
success: function (response) { success: function (response) {
if (response.status === 'success') { if (response && response.status === 'success') {
alert('Village added successfully!'); alert(response.message || 'Village added successfully!');
// ✅ clear form
$('#villageForm')[0].reset();
// ✅ switch to table
$('#addForm').hide();
$('#addTable').show();
// optional refresh
location.reload(); location.reload();
} else { } else {
alert(response.message || 'Error adding village. Please try again.'); alert(response.message || 'Error adding village. Please try again.');
} }
}, },
error: function () { error: function () {
alert('An error occurred. Please try again.'); alert('An error occurred. Please try again.');
}
});
});
} }
}); });
});
});
// 🔥 DELETE FUNCTION (UPDATED)
function deleteVillage(villageId) {
if (!confirm("Are you sure you want to delete this village?")) { // ===============================
return; // DELETE FUNCTION (SAFE)
} // ===============================
function deleteVillage(villageId, element) {
// ✅ save that user is on table if (!confirm("Are you sure you want to delete this village?")) return;
localStorage.setItem("viewMode", "table");
$.ajax({ $.ajax({
url: '/delete_village/' + villageId, url: '/delete_village/' + villageId,
type: 'GET', type: 'GET',
dataType: 'json',
success: function () { success: function (response) {
alert(response.message); // ✅ now shows "Village deleted successfully!"
setTimeout(function () { if (element) $(element).closest("tr").remove();
alert("Village deleted successfully!");
// reload but stay on table
location.reload();
}, 1000);
}, },
error: function () { error: function () {
alert("Error deleting village. Please try again."); alert("Error deleting village. Please try again.");
} }
}); });
} }

View File

@@ -1,22 +1,24 @@
{% extends 'base.html' %} {% extends 'base.html' %} {% block content %}
{% block content %}
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Village Management</title> <title>Village Management</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}"> <link
rel="stylesheet"
type="text/css"
href="{{ url_for('static', filename='css/style.css') }}"
/>
<script src="{{ url_for('static', filename='js/village.js') }}"></script> <script src="{{ url_for('static', filename='js/village.js') }}"></script>
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script> <script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
</head> </head>
<body> <body>
<!-- Button Container to Center Buttons --> <!-- Button Container to Center Buttons -->
<div class="button-container"> <div class="button-container">
<button id="addButton" class="action-button">Add</button> <button id="addButton" class="action-button">Add</button>
<button id="displayButton" class="action-button">Display</button> <button id="displayButton" class="action-button">Display</button>
</div> </div>
<div id="addForm" style="display: none;"> <div id="addForm" style="display: none">
<div class="container"> <div class="container">
<div class="form-block"> <div class="form-block">
<h2>Add a New Village</h2> <h2>Add a New Village</h2>
@@ -40,7 +42,13 @@
</select> </select>
<label for="Village_Name">Village Name:</label> <label for="Village_Name">Village Name:</label>
<input type="text" id="Village_Name" name="Village_Name" placeholder="Enter Village Name" required> <input
type="text"
id="Village_Name"
name="Village_Name"
placeholder="Enter Village Name"
required
/>
<span id="villageMessage"></span> <span id="villageMessage"></span>
<button type="submit" id="submitVillage" disabled>Add Village</button> <button type="submit" id="submitVillage" disabled>Add Village</button>
@@ -49,10 +57,15 @@
</div> </div>
</div> </div>
<div id="addTable" style="display: none;"> <div id="addTable" style="display: none">
<div class="search-container"> <div class="search-container">
<h2>Display Villages</h2> <h2>Display Villages</h2>
<input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()"> <input
type="text"
id="searchBar"
placeholder="Searching..."
onkeyup="searchTable()"
/>
</div> </div>
<table id="sortableTable" border="1"> <table id="sortableTable" border="1">
@@ -63,12 +76,15 @@
<span class="sort-buttons"> <span class="sort-buttons">
<span class="sort-asc">⬆️</span> <span class="sort-asc">⬆️</span>
<span class="sort-desc">⬇️</span> <span class="sort-desc">⬇️</span>
</span></th> </span>
<th class="sortable-header">Block Name </th>
<th class="sortable-header">
Block Name
<span class="sort-buttons"> <span class="sort-buttons">
<span class="sort-asc">⬆️</span> <span class="sort-asc">⬆️</span>
<span class="sort-desc">⬇️</span> <span class="sort-desc">⬇️</span>
</span></th> </span>
</th>
<th>Update</th> <th>Update</th>
<th>Delete</th> <th>Delete</th>
</tr> </tr>
@@ -78,22 +94,36 @@
<td>{{ village[1] }}</td> <td>{{ village[1] }}</td>
<td>{{ village[2] }}</td> <td>{{ village[2] }}</td>
<td> <td>
<a href="{{ url_for('village.edit_village', village_id=village[0]) }}"> <a
<img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit" href="{{ url_for('village.edit_village', village_id=village[0]) }}"
class="icon"> >
<img
src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}"
alt="Edit"
class="icon"
/>
</a> </a>
</td> </td>
<td> <td>
<a href="#" <a href="javascript:void(0);"
onclick="deleteVillage({{ village[0] }}); return false;"> onclick="deleteVillage({{ village[0] }}, this)">
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}" <img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}"
alt="Delete" class="icon"> class="icon">
</a> </a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>
</div> </div>
<!-- Flash Alerts -->
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<script>
{% for category, message in messages %}
alert("{{ message }}");
{% endfor %}
</script>
{% endif %}
{% endwith %}
</body> </body>
{% endblock %} {% endblock %}

View File

@@ -28,25 +28,17 @@
<button type="submit">Update Village</button> <button type="submit">Update Village</button>
</form> </form>
</div> <!-- Flash Messages (hidden, used for JS popup) -->
<div id="flash-messages-container" style="display:none;">
<!-- Flash Message (Hidden, used for JS popup) -->
{% with messages = get_flashed_messages(with_categories=true) %} {% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %} {% if messages %}
{% for category, message in messages %} {% for category, message in messages %}
<div id="flash-message" data-category="{{ category }}" style="display:none;">{{ message }}</div> <div class="flash-message" data-category="{{ category }}">{{ message }}</div>
{% endfor %} {% endfor %}
{% endif %} {% endif %}
{% endwith %} {% endwith %}
</div> </div>
<script>
window.onload = function () {
const flash = document.getElementById('flash-message');
if (flash && flash.innerText.trim() !== "") {
alert(flash.innerText);
}
};
</script>
</body> </body>
{% endblock %} {% endblock %}