feat: Implement ride management views and utility functions

- Added functions for checking user privileges, handling photo uploads, preparing form data, and managing form errors.
- Created views for listing, creating, updating, and displaying rides, including category-specific views.
- Integrated submission handling for ride changes and improved user feedback through messages.
- Enhanced data handling with appropriate context and queryset management for better performance and usability.
This commit is contained in:
pacnpal
2024-11-04 05:25:53 +00:00
parent ae913e757a
commit 01e0a609d2
29 changed files with 1087 additions and 925 deletions

View File

@@ -2225,6 +2225,14 @@ select {
z-index: 60;
}
.col-span-1 {
grid-column: span 1 / span 1;
}
.col-span-12 {
grid-column: span 12 / span 12;
}
.col-span-2 {
grid-column: span 2 / span 2;
}
@@ -2237,26 +2245,6 @@ select {
grid-column: 1 / -1;
}
.col-span-4 {
grid-column: span 4 / span 4;
}
.col-span-8 {
grid-column: span 8 / span 8;
}
.col-span-9 {
grid-column: span 9 / span 9;
}
.col-span-1 {
grid-column: span 1 / span 1;
}
.col-span-12 {
grid-column: span 12 / span 12;
}
.mx-1 {
margin-left: 0.25rem;
margin-right: 0.25rem;
@@ -2285,6 +2273,10 @@ select {
margin-bottom: 0.25rem;
}
.mb-10 {
margin-bottom: 2.5rem;
}
.mb-12 {
margin-bottom: 3rem;
}
@@ -2309,6 +2301,10 @@ select {
margin-bottom: 2rem;
}
.ml-0\.5 {
margin-left: 0.125rem;
}
.ml-1 {
margin-left: 0.25rem;
}
@@ -2321,6 +2317,10 @@ select {
margin-left: 1.5rem;
}
.mr-0\.5 {
margin-right: 0.125rem;
}
.mr-1 {
margin-right: 0.25rem;
}
@@ -2333,6 +2333,10 @@ select {
margin-right: 0.75rem;
}
.mt-0\.5 {
margin-top: 0.125rem;
}
.mt-1 {
margin-top: 0.25rem;
}
@@ -2357,38 +2361,6 @@ select {
margin-top: auto;
}
.mt-0\.5 {
margin-top: 0.125rem;
}
.mt-8 {
margin-top: 2rem;
}
.mr-1\.5 {
margin-right: 0.375rem;
}
.mb-0\.5 {
margin-bottom: 0.125rem;
}
.ml-0\.5 {
margin-left: 0.125rem;
}
.mr-0\.5 {
margin-right: 0.125rem;
}
.mt-1\.5 {
margin-top: 0.375rem;
}
.mb-10 {
margin-bottom: 2.5rem;
}
.block {
display: block;
}
@@ -2453,18 +2425,14 @@ select {
height: 300px;
}
.h-full {
height: 100%;
}
.h-\[340px\] {
height: 340px;
}
.h-auto {
height: auto;
}
.h-full {
height: 100%;
}
.max-h-60 {
max-height: 15rem;
}
@@ -2473,10 +2441,6 @@ select {
max-height: 90vh;
}
.max-h-\[340px\] {
max-height: 340px;
}
.min-h-\[calc\(100vh-16rem\)\] {
min-height: calc(100vh - 16rem);
}
@@ -2485,14 +2449,6 @@ select {
min-height: 100vh;
}
.min-h-0 {
min-height: 0px;
}
.min-h-\[200px\] {
min-height: 200px;
}
.w-16 {
width: 4rem;
}
@@ -2566,10 +2522,6 @@ select {
flex: 1 1 0%;
}
.flex-shrink-0 {
flex-shrink: 0;
}
.flex-grow {
flex-grow: 1;
}
@@ -2619,36 +2571,24 @@ select {
cursor: pointer;
}
.resize {
resize: both;
}
.auto-rows-fr {
grid-auto-rows: minmax(0, 1fr);
}
.auto-rows-min {
grid-auto-rows: min-content;
}
.grid-cols-1 {
grid-template-columns: repeat(1, minmax(0, 1fr));
}
.grid-cols-12 {
grid-template-columns: repeat(12, minmax(0, 1fr));
}
.grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.grid-cols-4 {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
.grid-cols-3 {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.grid-cols-12 {
grid-template-columns: repeat(12, minmax(0, 1fr));
.grid-cols-4 {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
.flex-col {
@@ -2683,6 +2623,10 @@ select {
justify-content: space-between;
}
.gap-1 {
gap: 0.25rem;
}
.gap-2 {
gap: 0.5rem;
}
@@ -2695,45 +2639,6 @@ select {
gap: 1.5rem;
}
.gap-3 {
gap: 0.75rem;
}
.gap-8 {
gap: 2rem;
}
.gap-1\.5 {
gap: 0.375rem;
}
.gap-1 {
gap: 0.25rem;
}
.gap-x-8 {
-moz-column-gap: 2rem;
column-gap: 2rem;
}
.gap-y-6 {
row-gap: 1.5rem;
}
.gap-x-6 {
-moz-column-gap: 1.5rem;
column-gap: 1.5rem;
}
.gap-y-4 {
row-gap: 1rem;
}
.gap-x-4 {
-moz-column-gap: 1rem;
column-gap: 1rem;
}
.space-x-2 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(0.5rem * var(--tw-space-x-reverse));
@@ -2784,10 +2689,6 @@ select {
overflow: hidden;
}
.overflow-y-auto {
overflow-y: auto;
}
.rounded {
border-radius: 0.25rem;
}
@@ -2923,6 +2824,11 @@ select {
background-color: rgb(37 99 235 / var(--tw-bg-opacity));
}
.bg-gray-100 {
--tw-bg-opacity: 1;
background-color: rgb(243 244 246 / var(--tw-bg-opacity));
}
.bg-gray-200 {
--tw-bg-opacity: 1;
background-color: rgb(229 231 235 / var(--tw-bg-opacity));
@@ -2991,11 +2897,6 @@ select {
background-color: rgb(202 138 4 / var(--tw-bg-opacity));
}
.bg-gray-100 {
--tw-bg-opacity: 1;
background-color: rgb(243 244 246 / var(--tw-bg-opacity));
}
.bg-opacity-50 {
--tw-bg-opacity: 0.5;
}
@@ -3047,6 +2948,14 @@ select {
object-fit: cover;
}
.p-0\.5 {
padding: 0.125rem;
}
.p-1\.5 {
padding: 0.375rem;
}
.p-2 {
padding: 0.5rem;
}
@@ -3067,18 +2976,6 @@ select {
padding: 2rem;
}
.p-2\.5 {
padding: 0.625rem;
}
.p-0\.5 {
padding: 0.125rem;
}
.p-1\.5 {
padding: 0.375rem;
}
.px-2 {
padding-left: 0.5rem;
padding-right: 0.5rem;
@@ -3104,6 +3001,11 @@ select {
padding-right: 2rem;
}
.py-0\.5 {
padding-top: 0.125rem;
padding-bottom: 0.125rem;
}
.py-1 {
padding-top: 0.25rem;
padding-bottom: 0.25rem;
@@ -3144,11 +3046,6 @@ select {
padding-bottom: 2rem;
}
.py-0\.5 {
padding-top: 0.125rem;
padding-bottom: 0.125rem;
}
.pb-4 {
padding-bottom: 1rem;
}
@@ -3157,10 +3054,6 @@ select {
text-align: center;
}
.align-middle {
vertical-align: middle;
}
.text-2xl {
font-size: 1.5rem;
line-height: 2rem;
@@ -3196,11 +3089,6 @@ select {
line-height: 1rem;
}
.text-base {
font-size: 1rem;
line-height: 1.5rem;
}
.font-bold {
font-weight: 700;
}
@@ -3237,6 +3125,11 @@ select {
color: rgb(30 64 175 / var(--tw-text-opacity));
}
.text-gray-200 {
--tw-text-opacity: 1;
color: rgb(229 231 235 / var(--tw-text-opacity));
}
.text-gray-300 {
--tw-text-opacity: 1;
color: rgb(209 213 219 / var(--tw-text-opacity));
@@ -3267,6 +3160,11 @@ select {
color: rgb(17 24 39 / var(--tw-text-opacity));
}
.text-green-600 {
--tw-text-opacity: 1;
color: rgb(22 163 74 / var(--tw-text-opacity));
}
.text-green-800 {
--tw-text-opacity: 1;
color: rgb(22 101 52 / var(--tw-text-opacity));
@@ -3297,6 +3195,11 @@ select {
color: rgb(153 27 27 / var(--tw-text-opacity));
}
.text-sky-900 {
--tw-text-opacity: 1;
color: rgb(12 74 110 / var(--tw-text-opacity));
}
.text-transparent {
color: transparent;
}
@@ -3326,21 +3229,6 @@ select {
color: rgb(133 77 14 / var(--tw-text-opacity));
}
.text-green-600 {
--tw-text-opacity: 1;
color: rgb(22 163 74 / var(--tw-text-opacity));
}
.text-sky-400 {
--tw-text-opacity: 1;
color: rgb(56 189 248 / var(--tw-text-opacity));
}
.text-sky-900 {
--tw-text-opacity: 1;
color: rgb(12 74 110 / var(--tw-text-opacity));
}
.opacity-0 {
opacity: 0;
}
@@ -3430,14 +3318,14 @@ select {
transition-duration: 150ms;
}
.transition-transform {
transition-property: transform;
.transition-shadow {
transition-property: box-shadow;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
.transition-shadow {
transition-property: box-shadow;
.transition-transform {
transition-property: transform;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
@@ -3496,11 +3384,6 @@ select {
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.hover\:translate-x-2:hover {
--tw-translate-x: 0.5rem;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.hover\:scale-105:hover {
--tw-scale-x: 1.05;
--tw-scale-y: 1.05;
@@ -3528,6 +3411,11 @@ select {
background-color: rgb(243 244 246 / var(--tw-bg-opacity));
}
.hover\:bg-gray-200:hover {
--tw-bg-opacity: 1;
background-color: rgb(229 231 235 / var(--tw-bg-opacity));
}
.hover\:bg-gray-300:hover {
--tw-bg-opacity: 1;
background-color: rgb(209 213 219 / var(--tw-bg-opacity));
@@ -3562,11 +3450,6 @@ select {
background-color: rgb(202 138 4 / var(--tw-bg-opacity));
}
.hover\:bg-gray-200:hover {
--tw-bg-opacity: 1;
background-color: rgb(229 231 235 / var(--tw-bg-opacity));
}
.hover\:text-blue-500:hover {
--tw-text-opacity: 1;
color: rgb(59 130 246 / var(--tw-text-opacity));
@@ -3606,31 +3489,11 @@ select {
color: rgb(79 70 229 / 0.8);
}
.hover\:text-sky-300:hover {
--tw-text-opacity: 1;
color: rgb(125 211 252 / var(--tw-text-opacity));
}
.hover\:text-sky-900:hover {
--tw-text-opacity: 1;
color: rgb(12 74 110 / var(--tw-text-opacity));
}
.hover\:text-sky-950:hover {
--tw-text-opacity: 1;
color: rgb(8 47 73 / var(--tw-text-opacity));
}
.hover\:text-sky-800:hover {
--tw-text-opacity: 1;
color: rgb(7 89 133 / var(--tw-text-opacity));
}
.hover\:text-blue-800:hover {
--tw-text-opacity: 1;
color: rgb(30 64 175 / var(--tw-text-opacity));
}
.hover\:underline:hover {
text-decoration-line: underline;
}
@@ -3641,6 +3504,12 @@ select {
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
.hover\:shadow-xl:hover {
--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
.focus\:border-blue-500:focus {
--tw-border-opacity: 1;
border-color: rgb(59 130 246 / var(--tw-border-opacity));
@@ -3853,6 +3722,11 @@ select {
color: rgb(187 247 208 / var(--tw-text-opacity));
}
.dark\:text-green-400:is(.dark *) {
--tw-text-opacity: 1;
color: rgb(74 222 128 / var(--tw-text-opacity));
}
.dark\:text-green-900:is(.dark *) {
--tw-text-opacity: 1;
color: rgb(20 83 45 / var(--tw-text-opacity));
@@ -3878,6 +3752,11 @@ select {
color: rgb(127 29 29 / var(--tw-text-opacity));
}
.dark\:text-sky-400:is(.dark *) {
--tw-text-opacity: 1;
color: rgb(56 189 248 / var(--tw-text-opacity));
}
.dark\:text-white:is(.dark *) {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
@@ -3903,16 +3782,6 @@ select {
color: rgb(254 252 232 / var(--tw-text-opacity));
}
.dark\:text-green-400:is(.dark *) {
--tw-text-opacity: 1;
color: rgb(74 222 128 / var(--tw-text-opacity));
}
.dark\:text-sky-400:is(.dark *) {
--tw-text-opacity: 1;
color: rgb(56 189 248 / var(--tw-text-opacity));
}
.dark\:ring-1:is(.dark *) {
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
@@ -3986,39 +3855,20 @@ select {
color: rgb(79 70 229 / var(--tw-text-opacity));
}
.dark\:hover\:text-sky-400:hover:is(.dark *) {
--tw-text-opacity: 1;
color: rgb(56 189 248 / var(--tw-text-opacity));
}
.dark\:hover\:text-sky-600:hover:is(.dark *) {
--tw-text-opacity: 1;
color: rgb(2 132 199 / var(--tw-text-opacity));
}
.dark\:hover\:text-sky-200:hover:is(.dark *) {
--tw-text-opacity: 1;
color: rgb(186 230 253 / var(--tw-text-opacity));
}
.dark\:hover\:text-sky-300:hover:is(.dark *) {
--tw-text-opacity: 1;
color: rgb(125 211 252 / var(--tw-text-opacity));
}
@media (min-width: 640px) {
.sm\:col-span-2 {
grid-column: span 2 / span 2;
.sm\:col-span-3 {
grid-column: span 3 / span 3;
}
.sm\:col-span-4 {
grid-column: span 4 / span 4;
}
.sm\:col-span-3 {
grid-column: span 3 / span 3;
}
.sm\:col-span-8 {
grid-column: span 8 / span 8;
}
@@ -4027,68 +3877,20 @@ select {
grid-column: span 9 / span 9;
}
.sm\:mb-8 {
margin-bottom: 2rem;
}
.sm\:mb-16 {
margin-bottom: 4rem;
}
.sm\:flex {
display: flex;
}
.sm\:h-\[340px\] {
height: 340px;
}
.sm\:h-\[300px\] {
height: 300px;
}
.sm\:h-\[200px\] {
height: 200px;
}
.sm\:h-\[160px\] {
height: 160px;
}
.sm\:h-\[140px\] {
height: 140px;
}
.sm\:h-auto {
height: auto;
}
.sm\:grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.sm\:grid-cols-6 {
grid-template-columns: repeat(6, minmax(0, 1fr));
}
.sm\:grid-cols-12 {
grid-template-columns: repeat(12, minmax(0, 1fr));
}
.sm\:grid-cols-4 {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
.sm\:grid-cols-1 {
grid-template-columns: repeat(1, minmax(0, 1fr));
}
.sm\:flex-col {
flex-direction: column;
.sm\:grid-cols-12 {
grid-template-columns: repeat(12, minmax(0, 1fr));
}
.sm\:gap-4 {
gap: 1rem;
.sm\:grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.sm\:space-x-4 > :not([hidden]) ~ :not([hidden]) {
@@ -4103,6 +3905,11 @@ select {
margin-left: calc(1.5rem * calc(1 - var(--tw-space-x-reverse)));
}
.sm\:text-2xl {
font-size: 1.5rem;
line-height: 2rem;
}
.sm\:text-3xl {
font-size: 1.875rem;
line-height: 2.25rem;
@@ -4118,52 +3925,18 @@ select {
line-height: 1.25rem;
}
.sm\:text-4xl {
font-size: 2.25rem;
line-height: 2.5rem;
}
.sm\:text-lg {
font-size: 1.125rem;
line-height: 1.75rem;
}
.sm\:text-xs {
font-size: 0.75rem;
line-height: 1rem;
}
.sm\:text-2xl {
font-size: 1.5rem;
line-height: 2rem;
.sm\:text-xl {
font-size: 1.25rem;
line-height: 1.75rem;
}
}
@media (min-width: 768px) {
.md\:col-span-2 {
grid-column: span 2 / span 2;
}
.md\:col-span-3 {
grid-column: span 3 / span 3;
}
.md\:col-span-9 {
grid-column: span 9 / span 9;
}
.md\:col-span-4 {
grid-column: span 4 / span 4;
}
.md\:col-span-8 {
grid-column: span 8 / span 8;
}
.md\:mt-0 {
margin-top: 0px;
}
.md\:mb-8 {
margin-bottom: 2rem;
}
@@ -4184,14 +3957,6 @@ select {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
.md\:grid-cols-8 {
grid-template-columns: repeat(8, minmax(0, 1fr));
}
.md\:grid-cols-12 {
grid-template-columns: repeat(12, minmax(0, 1fr));
}
.md\:flex-row {
flex-direction: row;
}
@@ -4200,10 +3965,6 @@ select {
align-items: center;
}
.md\:justify-between {
justify-content: space-between;
}
.md\:text-2xl {
font-size: 1.5rem;
line-height: 2rem;
@@ -4224,38 +3985,6 @@ select {
grid-column: span 2 / span 2;
}
.lg\:col-span-4 {
grid-column: span 4 / span 4;
}
.lg\:col-span-8 {
grid-column: span 8 / span 8;
}
.lg\:col-span-3 {
grid-column: span 3 / span 3;
}
.lg\:col-span-5 {
grid-column: span 5 / span 5;
}
.lg\:mb-0 {
margin-bottom: 0px;
}
.lg\:mr-6 {
margin-right: 1.5rem;
}
.lg\:ml-8 {
margin-left: 2rem;
}
.lg\:mt-0 {
margin-top: 0px;
}
.lg\:flex {
display: flex;
}
@@ -4264,18 +3993,6 @@ select {
display: none;
}
.lg\:w-1\/3 {
width: 33.333333%;
}
.lg\:w-1\/2 {
width: 50%;
}
.lg\:flex-1 {
flex: 1 1 0%;
}
.lg\:grid-cols-3 {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
@@ -4284,38 +4001,8 @@ select {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
.lg\:grid-cols-12 {
grid-template-columns: repeat(12, minmax(0, 1fr));
}
.lg\:grid-cols-5 {
grid-template-columns: repeat(5, minmax(0, 1fr));
}
.lg\:grid-cols-6 {
grid-template-columns: repeat(6, minmax(0, 1fr));
}
.lg\:flex-row {
flex-direction: row;
}
.lg\:items-start {
align-items: flex-start;
}
.lg\:justify-between {
justify-content: space-between;
}
.lg\:text-6xl {
font-size: 3.75rem;
line-height: 1;
}
}
@media (min-width: 1280px) {
.xl\:grid-cols-4 {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
}

View File

@@ -0,0 +1,91 @@
document.addEventListener('alpine:init', () => {
Alpine.data('photoDisplay', ({ photos, contentType, objectId, csrfToken, uploadUrl }) => ({
photos,
fullscreenPhoto: null,
uploading: false,
uploadProgress: 0,
error: null,
showSuccess: false,
showFullscreen(photo) {
this.fullscreenPhoto = photo;
},
async handleFileSelect(event) {
const files = Array.from(event.target.files);
if (!files.length) {
return;
}
this.uploading = true;
this.uploadProgress = 0;
this.error = null;
this.showSuccess = false;
const totalFiles = files.length;
let completedFiles = 0;
for (const file of files) {
const formData = new FormData();
formData.append('image', file);
formData.append('app_label', contentType.split('.')[0]);
formData.append('model', contentType.split('.')[1]);
formData.append('object_id', objectId);
try {
const response = await fetch(uploadUrl, {
method: 'POST',
headers: {
'X-CSRFToken': csrfToken,
},
body: formData
});
if (!response.ok) {
const data = await response.json();
throw new Error(data.error || 'Upload failed');
}
const photo = await response.json();
this.photos.push(photo);
completedFiles++;
this.uploadProgress = (completedFiles / totalFiles) * 100;
} catch (err) {
this.error = err.message || 'Failed to upload photo. Please try again.';
console.error('Upload error:', err);
break;
}
}
this.uploading = false;
event.target.value = ''; // Reset file input
if (!this.error) {
this.showSuccess = true;
setTimeout(() => {
this.showSuccess = false;
}, 3000);
}
},
async sharePhoto(photo) {
if (navigator.share) {
try {
await navigator.share({
title: photo.caption || 'Shared photo',
url: photo.url
});
} catch (err) {
if (err.name !== 'AbortError') {
console.error('Error sharing:', err);
}
}
} else {
// Fallback: copy URL to clipboard
navigator.clipboard.writeText(photo.url)
.then(() => alert('Photo URL copied to clipboard!'))
.catch(err => console.error('Error copying to clipboard:', err));
}
}
}));
});