117203307d
Removes visual clutter and simplifies the interface for better usability:
Layout simplification:
- Change column split from 4/8 to 5/7 for better balance
- Remove gradient backgrounds from card headers
- Use simple white headers with clean icons
- Increase spacing between sections (g-4 gap)
- Remove info cards at bottom to reduce page length
Form simplification:
- Remove input group icons and addons
- Use clean standalone inputs without decorations
- Remove helper text under each field (info in placeholder)
- Reduce button sizes from btn-lg to standard
- Remove decorative tip boxes
- Simpler labels without icons
- Reduce vertical spacing (mb-3 instead of mb-4)
Table simplification:
- Remove icons from table headers
- Cleaner header text ("Your Accounts" vs "Direct Deposit Accounts")
- Remove subtitle text from headers
Input styling:
- Smaller, cleaner inputs (0.5rem radius, 1px border)
- Smaller padding (0.625rem vs 0.875rem)
- Smaller font size (0.95rem)
- Subtle focus rings (3px glow)
- Color-coded focus: green for add, yellow for decrypt
- Removed complex gradients and shadows
The page now has a clean, uncluttered appearance with better
visual hierarchy and easier-to-scan content.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
457 lines
14 KiB
Plaintext
457 lines
14 KiB
Plaintext
<div class="container-fluid">
|
|
<!-- Header -->
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<h2 class="mb-3">
|
|
<i class="bi bi-bank text-primary"></i> Direct Deposit & Pay
|
|
</h2>
|
|
<p class="text-muted">Manage your direct deposit accounts and payment settings</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Alert Messages -->
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div id="success" style="display: none;" class="alert alert-success alert-dismissible fade show" role="alert">
|
|
<div class="d-flex align-items-center">
|
|
<i class="bi bi-check-circle-fill me-2" style="font-size: 1.5rem;"></i>
|
|
<div>
|
|
<h5 class="alert-heading mb-1">Success!</h5>
|
|
<p class="mb-0">Information successfully updated.</p>
|
|
</div>
|
|
</div>
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
</div>
|
|
|
|
<div id="failure" style="display: none;" class="alert alert-danger alert-dismissible fade show" role="alert">
|
|
<div class="d-flex align-items-center">
|
|
<i class="bi bi-exclamation-triangle-fill me-2" style="font-size: 1.5rem;"></i>
|
|
<div>
|
|
<h5 class="alert-heading mb-1">Error!</h5>
|
|
<p class="mb-0">Failed to update. Please try again.</p>
|
|
</div>
|
|
</div>
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row g-4">
|
|
<!-- Left Column - Forms -->
|
|
<div class="col-lg-5">
|
|
<!-- Add Direct Deposit Form -->
|
|
<div class="card shadow-sm mb-4">
|
|
<div class="card-header bg-white py-3">
|
|
<h5 class="mb-0">
|
|
<i class="bi bi-plus-circle text-success me-2"></i>Add Direct Deposit
|
|
</h5>
|
|
</div>
|
|
<div class="card-body p-4">
|
|
<%= form_tag "#", { class: "needs-validation", id: "bank_info_form" } do %>
|
|
<div class="mb-3">
|
|
<label class="form-label">Bank Account Number</label>
|
|
<%= text_field_tag :bank_account_num, params[:bank_account_num], {
|
|
placeholder: "Enter account number",
|
|
class: "form-control"
|
|
} %>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">Bank Routing Number</label>
|
|
<%= text_field_tag :bank_routing_num, params[:bank_routing_num], {
|
|
placeholder: "9-digit routing number",
|
|
class: "form-control"
|
|
} %>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">Percentage of Deposit</label>
|
|
<%= text_field_tag :dd_percent, params[:dd_percent], {
|
|
placeholder: "1-100",
|
|
class: "form-control"
|
|
} %>
|
|
</div>
|
|
|
|
<div class="d-grid mt-4">
|
|
<%= submit_tag "Add Account", {
|
|
id: "dd_form_btn",
|
|
class: "btn btn-success"
|
|
} %>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Decrypt Form -->
|
|
<div class="card shadow-sm">
|
|
<div class="card-header bg-white py-3">
|
|
<h5 class="mb-0">
|
|
<i class="bi bi-unlock text-warning me-2"></i>Decrypt Account
|
|
</h5>
|
|
</div>
|
|
<div class="card-body p-4">
|
|
<%= form_tag "#", { class: "needs-validation", id: "decrypt_form" } do %>
|
|
<div class="mb-3">
|
|
<label class="form-label">Encrypted Account Number</label>
|
|
<%= text_field_tag :value_to_decrypt, params[:value_to_decrypt], {
|
|
placeholder: "Paste encrypted value",
|
|
class: "form-control"
|
|
} %>
|
|
</div>
|
|
|
|
<div class="d-grid mt-4">
|
|
<%= submit_tag "Decrypt", {
|
|
id: "decrypt_btn",
|
|
class: "btn btn-warning"
|
|
} %>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Right Column - Accounts Table -->
|
|
<div class="col-lg-7">
|
|
<div class="card shadow-sm">
|
|
<div class="card-header bg-white py-3">
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<h5 class="mb-0">
|
|
<i class="bi bi-list-ul text-primary me-2"></i>Your Accounts
|
|
</h5>
|
|
<button type="button" class="btn btn-sm btn-outline-secondary" id="encrypted_acct_question">
|
|
<i class="bi bi-question-circle me-1"></i> Why Encrypted?
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="card-body p-0">
|
|
<div class="table-responsive">
|
|
<table class="table table-hover mb-0" id="data_table">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th>Account Number</th>
|
|
<th>Routing Number</th>
|
|
<th>Deposit %</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<!-- DataTable will populate this -->
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<%= javascript_include_tag "jquery.dataTables.min.js" %>
|
|
|
|
<script type="text/javascript">
|
|
|
|
/*
|
|
buildDeleteLink accepts a direct deposit ID and builds a link that enables
|
|
a user to delete that direct deposit entry
|
|
*/
|
|
function buildDeleteLink(dd_id){
|
|
var link = '<a href="/users/' + '<%= current_user.id %>' + '/pay/'+ dd_id + '" data-method="delete" rel="nofollow" class="btn btn-sm btn-outline-danger delete-row">' +
|
|
'<i class="bi bi-trash"></i> Delete</a>'
|
|
return link
|
|
};
|
|
|
|
/*
|
|
parseDirectDepositInfo accepts the response object and parses the JSON response, then
|
|
populates the direct deposit data table.
|
|
*/
|
|
function parseDirectDepostInfo(response){
|
|
var msg = jQuery.parseJSON(JSON.stringify(response));
|
|
var table = $('#data_table').DataTable();
|
|
|
|
$.each(msg.user, function(index, val){
|
|
table.row.add( [
|
|
'<code class="text-monospace">' + val.bank_account_num + '</code>',
|
|
'<span class="badge bg-light text-dark">' + val.bank_routing_num + '</span>',
|
|
'<span class="badge bg-success">' + val.percent_of_deposit + '%</span>',
|
|
buildDeleteLink(val.id)
|
|
] );
|
|
});
|
|
|
|
table.draw();
|
|
};
|
|
|
|
/*
|
|
createDataTable initializes the dd table as a datatable
|
|
*/
|
|
function createDataTable(){
|
|
// Check if DataTable is already initialized
|
|
if ($.fn.DataTable.isDataTable('#data_table')) {
|
|
$('#data_table').DataTable().destroy();
|
|
}
|
|
|
|
$('#data_table').DataTable({
|
|
"sPaginationType": "full_numbers",
|
|
"language": {
|
|
"emptyTable": "No direct deposit accounts configured yet"
|
|
},
|
|
"autoWidth": false,
|
|
"searching": true,
|
|
"ordering": true
|
|
});
|
|
};
|
|
|
|
/*
|
|
populateTable will first clear the existing dd table, then call the appropriate
|
|
endpoint to retrieve direct deposit entries and finally, provide parseDirectDepositInfo
|
|
with the response from the endpoint in order to populate the data table.
|
|
*/
|
|
function populateTable() {
|
|
var table = $('#data_table').DataTable();
|
|
table.clear();
|
|
|
|
$.ajax({
|
|
url: <%= sanitize(user_pay_path(:format => "json", user_id: current_user.id, id: current_user.id).inspect) %>,
|
|
type: "GET",
|
|
success: function(response) {
|
|
parseDirectDepostInfo(response);
|
|
},
|
|
error: function(event) {
|
|
$('#failure').show(500).delay(1500).fadeOut();
|
|
}
|
|
});
|
|
};
|
|
|
|
/*
|
|
This function doesn't really work right now but is supposed to offer the user a
|
|
"delete confirmation" message
|
|
*/
|
|
$(document).on('click', '.delete-row', function (e) {
|
|
var conf = confirm('Are you sure you want to delete this account?');
|
|
if (!conf) {
|
|
e.preventDefault();
|
|
return false;
|
|
}
|
|
});
|
|
|
|
/*
|
|
decryptShow parses the json response from the application and then renders
|
|
a decrypted version of the user's account number
|
|
*/
|
|
function decryptShow(response){
|
|
var msg = jQuery.parseJSON(JSON.stringify(response));
|
|
|
|
// Modern alert using Bootstrap modal-like appearance
|
|
var alertHtml = '<div class="alert alert-info alert-dismissible fade show" role="alert" style="position: fixed; top: 100px; left: 50%; transform: translateX(-50%); z-index: 9999; min-width: 400px; box-shadow: 0 4px 16px rgba(0,0,0,0.2);">' +
|
|
'<div class="d-flex align-items-center">' +
|
|
'<i class="bi bi-unlock-fill me-3" style="font-size: 2rem;"></i>' +
|
|
'<div>' +
|
|
'<h5 class="alert-heading mb-1">Decrypted Account Number</h5>' +
|
|
'<p class="mb-0"><strong style="font-size: 1.2rem; font-family: monospace;">' + msg.account_num + '</strong></p>' +
|
|
'</div>' +
|
|
'</div>' +
|
|
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
|
'</div>';
|
|
|
|
$('body').append(alertHtml);
|
|
|
|
// Auto-remove after 5 seconds
|
|
setTimeout(function() {
|
|
$('.alert').fadeOut(function() {
|
|
$(this).remove();
|
|
});
|
|
}, 5000);
|
|
};
|
|
|
|
/*
|
|
This function overrides the decrypt buttons (submit button's) native behavior,
|
|
allowing an ajax call to be made with the decrypt_form's inputs which is decrypted
|
|
server side with a JSON response containing the decrypted value. The decrypted value is
|
|
then passed to decryptShow();
|
|
*/
|
|
$("#decrypt_btn").click(function(event){
|
|
var valuesToSubmit = $("#decrypt_form").serialize();
|
|
event.preventDefault();
|
|
$.ajax({
|
|
url: <%= sanitize(decrypted_bank_acct_num_user_pay_index_path(:format => "json", user_id: current_user.id).inspect) %>,
|
|
data: valuesToSubmit,
|
|
type: "POST",
|
|
success: function(response) {
|
|
$('#success').show(500).delay(1500).fadeOut();
|
|
decryptShow(response);
|
|
$('#decrypt_form')[0].reset();
|
|
},
|
|
error: function(event) {
|
|
$('#failure').show(500).delay(1500).fadeOut();
|
|
}
|
|
});
|
|
});
|
|
|
|
/*
|
|
This function overrides the dd_form_btn's native behavior in order to submit an ajax request
|
|
that updates the user's direct deposit information. Upon success, the populateTable() function
|
|
is called in order to update the dataTable on the page to reflect the latest entry.
|
|
*/
|
|
$("#dd_form_btn").click(function(event) {
|
|
var valuesToSubmit = $("#bank_info_form").serialize();
|
|
event.preventDefault();
|
|
$.ajax({
|
|
url: <%= sanitize(update_dd_info_user_pay_index_path(:format => "json").inspect) %>,
|
|
data: valuesToSubmit,
|
|
type: "POST",
|
|
success: function(response) {
|
|
$('#success').show(500).delay(1500).fadeOut();
|
|
$('#bank_info_form')[0].reset();
|
|
populateTable();
|
|
},
|
|
error: function(event) {
|
|
$('#failure').show(500).delay(1500).fadeOut();
|
|
}
|
|
});
|
|
});
|
|
|
|
$("#encrypted_acct_question").click(function(event) {
|
|
event.preventDefault();
|
|
|
|
// Create modern Bootstrap modal-like alert
|
|
var modalHtml = '<div class="modal fade show d-block" tabindex="-1" style="background: rgba(0,0,0,0.5);">' +
|
|
'<div class="modal-dialog modal-dialog-centered">' +
|
|
'<div class="modal-content">' +
|
|
'<div class="modal-header" style="background: linear-gradient(135deg, rgba(69, 123, 157, 0.1), rgba(29, 53, 87, 0.1)); border-left: 4px solid var(--rg-secondary);">' +
|
|
'<h5 class="modal-title"><i class="bi bi-shield-lock-fill text-primary me-2"></i>Why Are Account Numbers Encrypted?</h5>' +
|
|
'<button type="button" class="btn-close" onclick="$(this).closest(\'.modal\').remove();"></button>' +
|
|
'</div>' +
|
|
'<div class="modal-body">' +
|
|
'<p class="mb-3"><i class="bi bi-check-circle-fill text-success me-2"></i><strong>For your safety</strong>, your account number is stored encrypted in our database and presented to you in an encrypted form.</p>' +
|
|
'<p class="mb-0"><i class="bi bi-unlock-fill text-warning me-2"></i><strong>For your convenience</strong>, you can decrypt your bank account number at any time using our conveniently located decryption function.</p>' +
|
|
'</div>' +
|
|
'<div class="modal-footer">' +
|
|
'<button type="button" class="btn btn-primary" onclick="$(this).closest(\'.modal\').remove();">Got It</button>' +
|
|
'</div>' +
|
|
'</div>' +
|
|
'</div>' +
|
|
'</div>';
|
|
|
|
$('body').append(modalHtml);
|
|
});
|
|
|
|
/*
|
|
Make the sidebar element "Pay" active.
|
|
*/
|
|
function makeActive(){
|
|
$('li[id="pay"]').addClass('active');
|
|
};
|
|
|
|
/*
|
|
Initialize page - called on both ready and turbolinks:load
|
|
*/
|
|
function initializePage() {
|
|
makeActive();
|
|
createDataTable();
|
|
populateTable();
|
|
}
|
|
|
|
// Handle normal page loads
|
|
$(document).ready(function() {
|
|
initializePage();
|
|
});
|
|
|
|
// Handle Turbolinks page loads
|
|
$(document).on('turbolinks:load', function() {
|
|
initializePage();
|
|
});
|
|
|
|
</script>
|
|
|
|
<style>
|
|
/* DataTables styling adjustments */
|
|
.dataTables_wrapper .dataTables_paginate .paginate_button {
|
|
padding: 0.375rem 0.75rem;
|
|
margin: 0 0.125rem;
|
|
border-radius: 0.5rem;
|
|
border: 1px solid #dee2e6;
|
|
background: white;
|
|
color: var(--rg-dark);
|
|
}
|
|
|
|
.dataTables_wrapper .dataTables_paginate .paginate_button:hover {
|
|
background: var(--rg-primary);
|
|
color: white;
|
|
border-color: var(--rg-primary);
|
|
}
|
|
|
|
.dataTables_wrapper .dataTables_paginate .paginate_button.current {
|
|
background: var(--rg-primary);
|
|
color: white;
|
|
border-color: var(--rg-primary);
|
|
}
|
|
|
|
.dataTables_filter input {
|
|
border-radius: 0.75rem;
|
|
border: 2px solid #e9ecef;
|
|
padding: 0.5rem 1rem;
|
|
}
|
|
|
|
.dataTables_filter input:focus {
|
|
border-color: var(--rg-primary);
|
|
outline: none;
|
|
box-shadow: 0 0 0 3px rgba(230, 57, 70, 0.1);
|
|
}
|
|
|
|
.text-monospace {
|
|
font-family: 'Courier New', monospace;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
/* Table hover effect */
|
|
#data_table tbody tr {
|
|
transition: background-color 0.2s ease;
|
|
}
|
|
|
|
#data_table tbody tr:hover {
|
|
background-color: rgba(230, 57, 70, 0.03);
|
|
}
|
|
|
|
/* Clean, minimal form controls */
|
|
.form-control {
|
|
border-radius: 0.5rem;
|
|
border: 1px solid #dee2e6;
|
|
padding: 0.625rem 0.875rem;
|
|
font-size: 0.95rem;
|
|
transition: all 0.2s ease;
|
|
}
|
|
|
|
.form-control:focus {
|
|
border-color: var(--rg-primary);
|
|
box-shadow: 0 0 0 3px rgba(230, 57, 70, 0.1);
|
|
outline: none;
|
|
}
|
|
|
|
#bank_info_form .form-control:focus {
|
|
border-color: var(--rg-success);
|
|
box-shadow: 0 0 0 3px rgba(6, 214, 160, 0.1);
|
|
}
|
|
|
|
#decrypt_form .form-control:focus {
|
|
border-color: var(--rg-warning);
|
|
box-shadow: 0 0 0 3px rgba(255, 183, 3, 0.1);
|
|
}
|
|
|
|
.form-label {
|
|
font-weight: 500;
|
|
color: var(--rg-dark);
|
|
margin-bottom: 0.4rem;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
/* Button styling */
|
|
.btn {
|
|
border-radius: 0.5rem;
|
|
font-weight: 500;
|
|
transition: all 0.2s ease;
|
|
}
|
|
|
|
.btn:hover {
|
|
transform: translateY(-1px);
|
|
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
|
|
}
|
|
</style>
|