Files
railsgoat/app/views/pay/index.html.erb
T
Ken Johnson c32ef4eb4f Increase border radius for modern rounded inputs and buttons
Makes form controls more rounded and polished instead of rectangular:

Form control updates:
- Increase border-radius from 0.5rem to 0.75rem for softer curves
- Increase border from 1px to 2px for better definition
- Adjust padding to 0.75rem 1rem for comfortable spacing
- Set font-size to 1rem for better readability

Button updates:
- Match border-radius at 0.75rem for consistency
- Increase font-weight to 600 for emphasis
- Add explicit padding (0.75rem 1.5rem)
- Stronger hover lift effect (translateY -2px)
- Enhanced shadow on hover (0 4px 12px)

Inputs and buttons now have modern, rounded appearance matching
the design system used throughout the application.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 03:23:59 -05:00

458 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.75rem;
border: 2px solid #e9ecef;
padding: 0.75rem 1rem;
font-size: 1rem;
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.75rem;
font-weight: 600;
transition: all 0.2s ease;
padding: 0.75rem 1.5rem;
}
.btn:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}
</style>