Skip to content

Commit

Permalink
Merge pull request #58 from Crudzaso/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
DiegoAndresRamirez authored Nov 11, 2024
2 parents f9d8408 + e10e8ee commit 597f5f2
Show file tree
Hide file tree
Showing 14 changed files with 608 additions and 2 deletions.
10 changes: 10 additions & 0 deletions app/Http/Controllers/UserController.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,16 @@ public function destroy(User $user)
$user->delete();

return redirect()->route('users.index')->with('success', 'Usuario eliminado exitosamente.');
}

public function showProfile(User $user)
{
if (auth()->id() !== $user->id) {
abort(403, 'No tienes permiso para ver este perfil.');
}

return Inertia::render('Users/Profile', [
'user' => $user,
]);
}
}
5 changes: 4 additions & 1 deletion app/Http/Middleware/HandleInertiaRequests.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace App\Http\Middleware;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Inertia\Middleware;

class HandleInertiaRequests extends Middleware
Expand Down Expand Up @@ -36,7 +37,9 @@ public function version(Request $request): ?string
public function share(Request $request): array
{
return array_merge(parent::share($request), [
//
'auth' => [
'user' => Auth::user(),
],
]);
}
}
4 changes: 4 additions & 0 deletions app/Providers/AppServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

namespace App\Providers;

use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
Expand All @@ -24,5 +26,7 @@ public function boot(): void
if ($this->app->environment('production')) {
URL::forceScheme('https');
}

View::share('authUser', Auth::user());
}
}
11 changes: 11 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"@splidejs/vue-splide": "^0.6.12",
"chart.js": "^4.4.6",
"lucide-vue-next": "^0.454.0",
"vue-chartjs": "^5.3.2",
"vue-router": "^4.4.5"
}
}
8 changes: 7 additions & 1 deletion resources/js/Components/Dashboard/NavBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@
</button>

<button class="btn-icon glow-effect">
<img :src="isDarkMode ? '/assets/media/gananza/user-light.svg' : '/assets/media/gananza/user-dark.svg'" alt="Perfil" class="icon-img" />
<a :href="`/profile/${authUser.id}`">
<img :src="isDarkMode ? '/assets/media/gananza/user-light.svg' : '/assets/media/gananza/user-dark.svg'" alt="Perfil" class="icon-img" />
</a>
</button>
</div>
</div>
Expand All @@ -61,6 +63,10 @@
import { Sun, Moon } from 'lucide-vue-next';
import { ref, computed } from 'vue';
import { useDarkMode } from '@/composables/useDarkMode';
import { usePage } from '@inertiajs/vue3';
const authUser = computed(() => usePage().props.auth.user);
const { isDarkMode, toggleDarkMode } = useDarkMode();
const isMenuOpen = ref(false);
Expand Down
107 changes: 107 additions & 0 deletions resources/js/Components/Profile/ActivityChart.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<template>
<div :class="[isDarkMode ? 'bg-[#1c1c1e] text-white' : 'bg-[#f9f9f9] text-gray-900', 'p-6 rounded-lg shadow-lg mb-8']">
<h2 class="text-xl font-semibold mb-4 text-center">Actividad de Tickets</h2>
<div class="chart-wrapper">
<Bar :data="chartData" :options="chartOptions" />
</div>
</div>
</template>
<script setup>
import { ref, computed, watch } from 'vue';
import { Bar } from 'vue-chartjs';
import {
Chart as ChartJS,
Title,
Tooltip,
Legend,
BarElement,
CategoryScale,
LinearScale,
} from 'chart.js';
import { useDarkMode } from '@/composables/useDarkMode';
// Registrar componentes de Chart.js
ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale);
const { isDarkMode } = useDarkMode();
const props = defineProps(['data']);
// Verificar si los datos son válidos
const isDataArray = computed(() => Array.isArray(props.data) && props.data.length > 0);
// Datos del gráfico
const chartData = ref({
labels: [],
datasets: [],
});
// Actualizar los datos del gráfico
const updateChartData = () => {
if (isDataArray.value) {
chartData.value = {
labels: props.data.map((item) => item.date),
datasets: [
{
label: 'Tickets',
data: props.data.map((item) => item.tickets),
backgroundColor: isDarkMode.value ? '#4f46e5' : '#2563eb',
borderColor: isDarkMode.value ? '#6366f1' : '#1d4ed8',
borderWidth: 1,
borderRadius: 8,
},
],
};
}
};
// Opciones del gráfico
const chartOptions = computed(() => ({
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: true,
labels: {
color: isDarkMode.value ? '#E0E0E0' : '#212121',
font: { size: 14 },
},
},
tooltip: {
enabled: true,
backgroundColor: isDarkMode.value ? '#333' : '#fff',
titleColor: isDarkMode.value ? '#fff' : '#000',
bodyColor: isDarkMode.value ? '#ddd' : '#333',
},
},
scales: {
x: {
grid: { display: false },
ticks: { color: isDarkMode.value ? '#E0E0E0' : '#212121' },
},
y: {
grid: { color: isDarkMode.value ? '#3a3a3c' : '#e0e0e0' },
ticks: { color: isDarkMode.value ? '#E0E0E0' : '#212121' },
},
},
}));
// Observar cambios en los datos y actualizar el gráfico
watch(() => props.data, updateChartData, { immediate: true });
</script>

<style scoped>
.chart-wrapper {
height: 300px;
max-height: 400px;
overflow: hidden;
}
h2 {
text-align: center;
}
.chart-container {
position: relative;
height: 300px;
}
</style>
67 changes: 67 additions & 0 deletions resources/js/Components/Profile/PersonalField.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<template>
<div class="mb-4">
<label :class="`${isDarkMode ? 'text-gray-400' : 'text-gray-600'}`" class="block mb-1 font-semibold">
{{ label }}
</label>
<input
:type="type"
v-model="localValue"
:placeholder="placeholder"
class="mt-1 block w-full rounded-md border p-2"
:class="`${isDarkMode ? 'bg-[#1a1a1c] border-gray-600 text-white' : 'bg-white border-gray-300 text-gray-900'}`"
/>
</div>
</template>

<script setup>
import { ref, watch } from 'vue';
import { useDarkMode } from '@/composables/useDarkMode';
// Definir las props usando defineProps
const props = defineProps({
label: {
type: String,
required: true,
},
value: {
type: String,
default: '',
},
type: {
type: String,
default: 'text',
},
placeholder: {
type: String,
default: '',
},
});
// Definir emit para permitir la comunicación con el padre
const emit = defineEmits(['update:value']);
const { isDarkMode } = useDarkMode();
// Crear una referencia local para manejar el valor del input
const localValue = ref(props.value);
// Sincronizar los cambios del input con el componente padre
watch(localValue, (newValue) => {
emit('update:value', newValue);
});
// Actualizar el valor local si cambia la prop `value` desde el padre
watch(
() => props.value,
(newValue) => {
localValue.value = newValue;
}
);
</script>

<style scoped>
/* Estilos adicionales */
input:focus {
outline: none;
box-shadow: 0 0 10px rgba(0, 191, 255, 0.3);
}
</style>
96 changes: 96 additions & 0 deletions resources/js/Components/Profile/PersonalInfo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<template>
<div :class="`${isDarkMode ? 'bg-[#242426] text-white' : 'bg-white'} p-6 rounded-lg shadow-lg mb-8`">
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- Renderizamos dinámicamente los campos del usuario -->
<PersonalField
v-for="(value, key) in userFields"
:key="key"
:label="formatLabel(key)"
:type="getInputType(key)"
v-model="user[key]"
:placeholder="getPlaceholder(key)"
/>
</div>
</div>
</template>

<script setup>
import { useDarkMode } from '@/composables/useDarkMode';
import PersonalField from '@/Components/Profile/PersonalField.vue';
import { defineProps, computed } from 'vue';
const { isDarkMode } = useDarkMode();
// Define la prop `user`
const props = defineProps({
user: {
type: Object,
default: () => ({
name: '',
email: '',
phone: '',
address: '',
country: '',
}),
},
});
// Computed para obtener los campos del usuario dinámicamente
const userFields = computed(() => props.user);
// Función para formatear el label
const formatLabel = (key) => {
switch (key) {
case 'name':
return 'Nombre Completo';
case 'email':
return 'Correo Electrónico';
case 'phone':
return 'Teléfono';
case 'address':
return 'Dirección';
case 'country':
return 'País';
default:
return key.charAt(0).toUpperCase() + key.slice(1);
}
};
// Función para obtener el tipo de input
const getInputType = (key) => {
switch (key) {
case 'email':
return 'email';
case 'phone':
return 'tel';
default:
return 'text';
}
};
// Función para obtener el placeholder
const getPlaceholder = (key) => {
switch (key) {
case 'name':
return 'Ingresa tu nombre';
case 'email':
return 'Ingresa tu correo';
case 'phone':
return 'Ingresa tu número de teléfono';
case 'address':
return 'Ingresa tu dirección';
case 'country':
return 'Ingresa tu país';
default:
return `Ingresa tu ${key}`;
}
};
</script>

<style scoped>
/* Estilo adicional */
input:focus {
outline: none;
box-shadow: 0 0 10px rgba(0, 191, 255, 0.3);
}
</style>
Loading

0 comments on commit 597f5f2

Please sign in to comment.