parent
766eaa3234
commit
992c21bc3e
|
|
@ -0,0 +1,66 @@
|
|||
APP_NAME=Laravel
|
||||
APP_ENV=local
|
||||
APP_KEY=base64:iHPDeCnviINzk4hSncvHa8qFuz+iPW99xH+dHwxMhxQ=
|
||||
APP_DEBUG=true
|
||||
APP_TIMEZONE=UTC
|
||||
APP_URL=http://localhost
|
||||
|
||||
APP_LOCALE=en
|
||||
APP_FALLBACK_LOCALE=en
|
||||
APP_FAKER_LOCALE=en_US
|
||||
|
||||
APP_MAINTENANCE_DRIVER=file
|
||||
APP_MAINTENANCE_STORE=database
|
||||
|
||||
BCRYPT_ROUNDS=12
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
LOG_STACK=single
|
||||
LOG_DEPRECATIONS_CHANNEL=null
|
||||
LOG_LEVEL=debug
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=greenview
|
||||
DB_USERNAME=root
|
||||
DB_PASSWORD=
|
||||
|
||||
FONNTE_TOKEN=CEAJquyLniASpRf76eT9
|
||||
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
SESSION_ENCRYPT=false
|
||||
SESSION_PATH=/
|
||||
SESSION_DOMAIN=null
|
||||
|
||||
BROADCAST_CONNECTION=log
|
||||
FILESYSTEM_DISK=local
|
||||
QUEUE_CONNECTION=database
|
||||
|
||||
CACHE_STORE=database
|
||||
CACHE_PREFIX=
|
||||
|
||||
MEMCACHED_HOST=127.0.0.1
|
||||
|
||||
REDIS_CLIENT=phpredis
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=smtp.gmail.com
|
||||
MAIL_PORT=587
|
||||
MAIL_USERNAME=reyfandi3008@gmail.com
|
||||
MAIL_PASSWORD=hhre xxfh fcyj xlck
|
||||
MAIL_ENCRYPTION=tls
|
||||
MAIL_FROM_ADDRESS=reyfandi3008@gmail.com
|
||||
MAIL_FROM_NAME="Green View"
|
||||
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
AWS_BUCKET=
|
||||
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||
|
||||
VITE_APP_NAME="${APP_NAME}"
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
APP_NAME=Laravel
|
||||
APP_ENV=local
|
||||
APP_KEY=base64:iHPDeCnviINzk4hSncvHa8qFuz+iPW99xH+dHwxMhxQ=
|
||||
APP_DEBUG=true
|
||||
APP_TIMEZONE=UTC
|
||||
APP_URL=http://localhost
|
||||
|
||||
APP_LOCALE=en
|
||||
APP_FALLBACK_LOCALE=en
|
||||
APP_FAKER_LOCALE=en_US
|
||||
|
||||
APP_MAINTENANCE_DRIVER=file
|
||||
APP_MAINTENANCE_STORE=database
|
||||
|
||||
BCRYPT_ROUNDS=12
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
LOG_STACK=single
|
||||
LOG_DEPRECATIONS_CHANNEL=null
|
||||
LOG_LEVEL=debug
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=greenview
|
||||
DB_USERNAME=root
|
||||
DB_PASSWORD=
|
||||
|
||||
FONNTE_TOKEN=CEAJquyLniASpRf76eT9
|
||||
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
SESSION_ENCRYPT=false
|
||||
SESSION_PATH=/
|
||||
SESSION_DOMAIN=null
|
||||
|
||||
BROADCAST_CONNECTION=log
|
||||
FILESYSTEM_DISK=local
|
||||
QUEUE_CONNECTION=database
|
||||
|
||||
CACHE_STORE=database
|
||||
CACHE_PREFIX=
|
||||
|
||||
MEMCACHED_HOST=127.0.0.1
|
||||
|
||||
REDIS_CLIENT=phpredis
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=smtp.gmail.com
|
||||
MAIL_PORT=587
|
||||
MAIL_USERNAME=reyfandi3008@gmail.com
|
||||
MAIL_PASSWORD=hhre xxfh fcyjxlck
|
||||
MAIL_ENCRYPTION=tls
|
||||
MAIL_FROM_ADDRESS=reyfandi3008@gmail.com
|
||||
MAIL_FROM_NAME="Green View"
|
||||
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
AWS_BUCKET=
|
||||
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||
|
||||
VITE_APP_NAME="${APP_NAME}"
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
APP_NAME=Laravel
|
||||
APP_ENV=local
|
||||
APP_KEY=base64:iHPDeCnviINzk4hSncvHa8qFuz+iPW99xH+dHwxMhxQ=
|
||||
APP_DEBUG=true
|
||||
APP_TIMEZONE=UTC
|
||||
APP_URL=http://localhost
|
||||
|
||||
APP_LOCALE=en
|
||||
APP_FALLBACK_LOCALE=en
|
||||
APP_FAKER_LOCALE=en_US
|
||||
|
||||
APP_MAINTENANCE_DRIVER=file
|
||||
APP_MAINTENANCE_STORE=database
|
||||
|
||||
BCRYPT_ROUNDS=12
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
LOG_STACK=single
|
||||
LOG_DEPRECATIONS_CHANNEL=null
|
||||
LOG_LEVEL=debug
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=greenview
|
||||
DB_USERNAME=root
|
||||
DB_PASSWORD=
|
||||
|
||||
FONNTE_TOKEN=CEAJquyLniASpRf76eT9
|
||||
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
SESSION_ENCRYPT=false
|
||||
SESSION_PATH=/
|
||||
SESSION_DOMAIN=null
|
||||
|
||||
BROADCAST_CONNECTION=log
|
||||
FILESYSTEM_DISK=local
|
||||
QUEUE_CONNECTION=database
|
||||
|
||||
CACHE_STORE=database
|
||||
CACHE_PREFIX=
|
||||
|
||||
MEMCACHED_HOST=127.0.0.1
|
||||
|
||||
REDIS_CLIENT=phpredis
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=smtp.gmail.com
|
||||
MAIL_PORT=587
|
||||
MAIL_USERNAME=reyfandi3008@gmail.com
|
||||
MAIL_PASSWORD=hhre xxfhfcyjxlck
|
||||
MAIL_ENCRYPTION=tls
|
||||
MAIL_FROM_ADDRESS=reyfandi3008@gmail.com
|
||||
MAIL_FROM_NAME="Green View"
|
||||
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
AWS_BUCKET=
|
||||
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||
|
||||
VITE_APP_NAME="${APP_NAME}"
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
APP_NAME=Laravel
|
||||
APP_ENV=local
|
||||
APP_KEY=base64:iHPDeCnviINzk4hSncvHa8qFuz+iPW99xH+dHwxMhxQ=
|
||||
APP_DEBUG=true
|
||||
APP_TIMEZONE=UTC
|
||||
APP_URL=http://localhost
|
||||
|
||||
APP_LOCALE=en
|
||||
APP_FALLBACK_LOCALE=en
|
||||
APP_FAKER_LOCALE=en_US
|
||||
|
||||
APP_MAINTENANCE_DRIVER=file
|
||||
APP_MAINTENANCE_STORE=database
|
||||
|
||||
BCRYPT_ROUNDS=12
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
LOG_STACK=single
|
||||
LOG_DEPRECATIONS_CHANNEL=null
|
||||
LOG_LEVEL=debug
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=greenview
|
||||
DB_USERNAME=root
|
||||
DB_PASSWORD=
|
||||
|
||||
FONNTE_TOKEN=CEAJquyLniASpRf76eT9
|
||||
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
SESSION_ENCRYPT=false
|
||||
SESSION_PATH=/
|
||||
SESSION_DOMAIN=null
|
||||
|
||||
BROADCAST_CONNECTION=log
|
||||
FILESYSTEM_DISK=local
|
||||
QUEUE_CONNECTION=database
|
||||
|
||||
CACHE_STORE=database
|
||||
CACHE_PREFIX=
|
||||
|
||||
MEMCACHED_HOST=127.0.0.1
|
||||
|
||||
REDIS_CLIENT=phpredis
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=smtp.gmail.com
|
||||
MAIL_PORT=587
|
||||
MAIL_USERNAME=rtgreenview@gmail.com@gmail.com
|
||||
MAIL_PASSWORD=hhre xxfhfcyjxlck
|
||||
MAIL_ENCRYPTION=tls
|
||||
MAIL_FROM_ADDRESS=reyfandi3008@gmail.com
|
||||
MAIL_FROM_NAME="Green View"
|
||||
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
AWS_BUCKET=
|
||||
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||
|
||||
VITE_APP_NAME="${APP_NAME}"
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
APP_NAME=Laravel
|
||||
APP_ENV=local
|
||||
APP_KEY=base64:iHPDeCnviINzk4hSncvHa8qFuz+iPW99xH+dHwxMhxQ=
|
||||
APP_DEBUG=true
|
||||
APP_TIMEZONE=UTC
|
||||
APP_URL=http://localhost
|
||||
|
||||
APP_LOCALE=en
|
||||
APP_FALLBACK_LOCALE=en
|
||||
APP_FAKER_LOCALE=en_US
|
||||
|
||||
APP_MAINTENANCE_DRIVER=file
|
||||
APP_MAINTENANCE_STORE=database
|
||||
|
||||
BCRYPT_ROUNDS=12
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
LOG_STACK=single
|
||||
LOG_DEPRECATIONS_CHANNEL=null
|
||||
LOG_LEVEL=debug
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=greenview
|
||||
DB_USERNAME=root
|
||||
DB_PASSWORD=
|
||||
|
||||
FONNTE_TOKEN=CEAJquyLniASpRf76eT9
|
||||
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
SESSION_ENCRYPT=false
|
||||
SESSION_PATH=/
|
||||
SESSION_DOMAIN=null
|
||||
|
||||
BROADCAST_CONNECTION=log
|
||||
FILESYSTEM_DISK=local
|
||||
QUEUE_CONNECTION=database
|
||||
|
||||
CACHE_STORE=database
|
||||
CACHE_PREFIX=
|
||||
|
||||
MEMCACHED_HOST=127.0.0.1
|
||||
|
||||
REDIS_CLIENT=phpredis
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=smtp.gmail.com
|
||||
MAIL_PORT=587
|
||||
MAIL_USERNAME=rtgreenview@gmail.com@gmail.com
|
||||
MAIL_PASSWORD=hhre xxfhfcyjxlck
|
||||
MAIL_ENCRYPTION=tls
|
||||
MAIL_FROM_ADDRESS=rtgreenview@gmail.com
|
||||
MAIL_FROM_NAME="Green View"
|
||||
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
AWS_BUCKET=
|
||||
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||
|
||||
VITE_APP_NAME="${APP_NAME}"
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
APP_NAME=Laravel
|
||||
APP_ENV=local
|
||||
APP_KEY=base64:iHPDeCnviINzk4hSncvHa8qFuz+iPW99xH+dHwxMhxQ=
|
||||
APP_DEBUG=true
|
||||
APP_TIMEZONE=UTC
|
||||
APP_URL=http://localhost
|
||||
|
||||
APP_LOCALE=en
|
||||
APP_FALLBACK_LOCALE=en
|
||||
APP_FAKER_LOCALE=en_US
|
||||
|
||||
APP_MAINTENANCE_DRIVER=file
|
||||
APP_MAINTENANCE_STORE=database
|
||||
|
||||
BCRYPT_ROUNDS=12
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
LOG_STACK=single
|
||||
LOG_DEPRECATIONS_CHANNEL=null
|
||||
LOG_LEVEL=debug
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=greenview
|
||||
DB_USERNAME=root
|
||||
DB_PASSWORD=
|
||||
|
||||
FONNTE_TOKEN=CEAJquyLniASpRf76eT9
|
||||
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
SESSION_ENCRYPT=false
|
||||
SESSION_PATH=/
|
||||
SESSION_DOMAIN=null
|
||||
|
||||
BROADCAST_CONNECTION=log
|
||||
FILESYSTEM_DISK=local
|
||||
QUEUE_CONNECTION=database
|
||||
|
||||
CACHE_STORE=database
|
||||
CACHE_PREFIX=
|
||||
|
||||
MEMCACHED_HOST=127.0.0.1
|
||||
|
||||
REDIS_CLIENT=phpredis
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=smtp.gmail.com
|
||||
MAIL_PORT=587
|
||||
MAIL_USERNAME=rtgreenview@gmail.com@gmail.com
|
||||
MAIL_PASSWORD=hhrexxfhfcyjxlck
|
||||
MAIL_ENCRYPTION=tls
|
||||
MAIL_FROM_ADDRESS=rtgreenview@gmail.com
|
||||
MAIL_FROM_NAME="Green View"
|
||||
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
AWS_BUCKET=
|
||||
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||
|
||||
VITE_APP_NAME="${APP_NAME}"
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
APP_NAME=Laravel
|
||||
APP_ENV=local
|
||||
APP_KEY=base64:iHPDeCnviINzk4hSncvHa8qFuz+iPW99xH+dHwxMhxQ=
|
||||
APP_DEBUG=true
|
||||
APP_TIMEZONE=UTC
|
||||
APP_URL=http://localhost
|
||||
|
||||
APP_LOCALE=en
|
||||
APP_FALLBACK_LOCALE=en
|
||||
APP_FAKER_LOCALE=en_US
|
||||
|
||||
APP_MAINTENANCE_DRIVER=file
|
||||
APP_MAINTENANCE_STORE=database
|
||||
|
||||
BCRYPT_ROUNDS=12
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
LOG_STACK=single
|
||||
LOG_DEPRECATIONS_CHANNEL=null
|
||||
LOG_LEVEL=debug
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=greenview
|
||||
DB_USERNAME=root
|
||||
DB_PASSWORD=
|
||||
|
||||
FONNTE_TOKEN=CEAJquyLniASpRf76eT9
|
||||
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
SESSION_ENCRYPT=false
|
||||
SESSION_PATH=/
|
||||
SESSION_DOMAIN=null
|
||||
|
||||
BROADCAST_CONNECTION=log
|
||||
FILESYSTEM_DISK=local
|
||||
QUEUE_CONNECTION=database
|
||||
|
||||
CACHE_STORE=database
|
||||
CACHE_PREFIX=
|
||||
|
||||
MEMCACHED_HOST=127.0.0.1
|
||||
|
||||
REDIS_CLIENT=phpredis
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=smtp.gmail.com
|
||||
MAIL_PORT=587
|
||||
MAIL_USERNAME=rtgreenview@gmail.com@gmail.com
|
||||
MAIL_PASSWORD=hhrexxfhfcyjxlck
|
||||
MAIL_ENCRYPTION=tls
|
||||
MAIL_FROM_ADDRESS=rtgreenview@gmail.com
|
||||
MAIL_FROM_NAME="Green View"
|
||||
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
AWS_BUCKET=
|
||||
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||
|
||||
VITE_APP_NAME="${APP_NAME}"
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
APP_NAME=Laravel
|
||||
APP_ENV=local
|
||||
APP_KEY=base64:iHPDeCnviINzk4hSncvHa8qFuz+iPW99xH+dHwxMhxQ=
|
||||
APP_DEBUG=true
|
||||
APP_TIMEZONE=UTC
|
||||
APP_URL=http://localhost
|
||||
|
||||
APP_LOCALE=en
|
||||
APP_FALLBACK_LOCALE=en
|
||||
APP_FAKER_LOCALE=en_US
|
||||
|
||||
APP_MAINTENANCE_DRIVER=file
|
||||
APP_MAINTENANCE_STORE=database
|
||||
|
||||
BCRYPT_ROUNDS=12
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
LOG_STACK=single
|
||||
LOG_DEPRECATIONS_CHANNEL=null
|
||||
LOG_LEVEL=debug
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=greenview
|
||||
DB_USERNAME=root
|
||||
DB_PASSWORD=
|
||||
|
||||
FONNTE_TOKEN=CEAJquyLniASpRf76eT9
|
||||
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
SESSION_ENCRYPT=false
|
||||
SESSION_PATH=/
|
||||
SESSION_DOMAIN=null
|
||||
|
||||
BROADCAST_CONNECTION=log
|
||||
FILESYSTEM_DISK=local
|
||||
QUEUE_CONNECTION=database
|
||||
|
||||
CACHE_STORE=database
|
||||
CACHE_PREFIX=
|
||||
|
||||
MEMCACHED_HOST=127.0.0.1
|
||||
|
||||
REDIS_CLIENT=phpredis
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=smtp.gmail.com
|
||||
MAIL_PORT=587
|
||||
MAIL_USERNAME=rtgreenview@gmail.com@gmail.com
|
||||
MAIL_PASSWORD=hhrexxfhfcyjxlck
|
||||
MAIL_ENCRYPTION=tls
|
||||
MAIL_FROM_ADDRESS=rtgreenview@gmail.com
|
||||
MAIL_FROM_NAME="Green View"
|
||||
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
AWS_BUCKET=
|
||||
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||
|
||||
VITE_APP_NAME="${APP_NAME}"
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
APP_NAME=Laravel
|
||||
APP_ENV=local
|
||||
APP_KEY=base64:iHPDeCnviINzk4hSncvHa8qFuz+iPW99xH+dHwxMhxQ=
|
||||
APP_DEBUG=true
|
||||
APP_TIMEZONE=UTC
|
||||
APP_URL=http://localhost
|
||||
|
||||
APP_LOCALE=en
|
||||
APP_FALLBACK_LOCALE=en
|
||||
APP_FAKER_LOCALE=en_US
|
||||
|
||||
APP_MAINTENANCE_DRIVER=file
|
||||
APP_MAINTENANCE_STORE=database
|
||||
|
||||
BCRYPT_ROUNDS=12
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
LOG_STACK=single
|
||||
LOG_DEPRECATIONS_CHANNEL=null
|
||||
LOG_LEVEL=debug
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=greenview
|
||||
DB_USERNAME=root
|
||||
DB_PASSWORD=
|
||||
|
||||
FONNTE_TOKEN=CEAJquyLniASpRf76eT9
|
||||
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
SESSION_ENCRYPT=false
|
||||
SESSION_PATH=/
|
||||
SESSION_DOMAIN=null
|
||||
|
||||
BROADCAST_CONNECTION=log
|
||||
FILESYSTEM_DISK=local
|
||||
QUEUE_CONNECTION=database
|
||||
|
||||
CACHE_STORE=database
|
||||
CACHE_PREFIX=
|
||||
|
||||
MEMCACHED_HOST=127.0.0.1
|
||||
|
||||
REDIS_CLIENT=phpredis
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=smtp.gmail.com
|
||||
MAIL_PORT=587
|
||||
MAIL_USERNAME=rtgreenview@gmail.com
|
||||
MAIL_PASSWORD=hhrexxfhfcyjxlck
|
||||
MAIL_ENCRYPTION=tls
|
||||
MAIL_FROM_ADDRESS=rtgreenview@gmail.com
|
||||
MAIL_FROM_NAME="Green View"
|
||||
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
AWS_BUCKET=
|
||||
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||
|
||||
VITE_APP_NAME="${APP_NAME}"
|
||||
|
|
@ -0,0 +1,490 @@
|
|||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
*, *::before, *::after { box-sizing: border-box; }
|
||||
body { font-family: 'Plus Jakarta Sans', sans-serif; }
|
||||
|
||||
/* ── PAGE HEADER ── */
|
||||
.page-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
.page-header-icon {
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
background: linear-gradient(135deg, #064e3b, #0d6e4f);
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
font-size: 20px;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0 4px 14px rgba(6,78,59,0.3);
|
||||
}
|
||||
.page-header h1 {
|
||||
font-size: 22px;
|
||||
font-weight: 800;
|
||||
color: #1a2e1a;
|
||||
margin: 0;
|
||||
line-height: 1.2;
|
||||
}
|
||||
.page-header p {
|
||||
font-size: 13px;
|
||||
color: #8a9e8a;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ── ALERT ── */
|
||||
.alert-success-custom {
|
||||
background: #f0faf4;
|
||||
border: 1px solid #a8e6be;
|
||||
border-left: 4px solid #1a6e3a;
|
||||
border-radius: 12px;
|
||||
padding: 12px 16px;
|
||||
color: #1a4e2a;
|
||||
font-size: 13.5px;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
/* ── CARD ── */
|
||||
.premium-card {
|
||||
background: #ffffff;
|
||||
border-radius: 16px;
|
||||
border: 1px solid #e8f0e8;
|
||||
box-shadow: 0 2px 12px rgba(0,0,0,0.05);
|
||||
margin-bottom: 24px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.premium-card-header {
|
||||
padding: 16px 22px;
|
||||
background: #ffffff;
|
||||
border-bottom: 1px solid #f0f5f0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.premium-card-header .header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
.header-icon {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
border-radius: 9px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 15px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.header-icon.green { background: #d1fae5; color: #064e3b; }
|
||||
.premium-card-header h6 {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: #1a2e1a;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ── TABLE ── */
|
||||
.premium-table {
|
||||
width: 100%;
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
font-size: 13px;
|
||||
}
|
||||
.premium-table thead tr th {
|
||||
background: #f6fbf7;
|
||||
color: #3a5a3a;
|
||||
font-weight: 700;
|
||||
font-size: 11.5px;
|
||||
letter-spacing: 0.5px;
|
||||
text-transform: uppercase;
|
||||
padding: 11px 14px;
|
||||
border-bottom: 2px solid #e0ede0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.premium-table thead tr th:first-child { border-radius: 10px 0 0 0; }
|
||||
.premium-table thead tr th:last-child { border-radius: 0 10px 0 0; }
|
||||
.premium-table tbody tr td {
|
||||
padding: 11px 14px;
|
||||
border-bottom: 1px solid #f2f7f2;
|
||||
color: #2a3a2a;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.premium-table tbody tr:hover td { background: #f8fdf8; }
|
||||
.premium-table tbody tr:last-child td { border-bottom: none; }
|
||||
|
||||
/* ── BADGES ── */
|
||||
.badge-pill-custom {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 99px;
|
||||
font-size: 11.5px;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.badge-green { background: #d1fae5; color: #064e3b; }
|
||||
.badge-red { background: #fdf0f0; color: #c53030; }
|
||||
.badge-yellow { background: #fdfbea; color: #7a6010; }
|
||||
.badge-blue { background: #eaf0fb; color: #1a4e8e; }
|
||||
.badge-gray { background: #f3f4f6; color: #4b5563; }
|
||||
|
||||
/* ── ACTION BUTTONS ── */
|
||||
.btn-action {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
padding: 5px 11px;
|
||||
border-radius: 8px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
text-decoration: none;
|
||||
transition: opacity 0.15s, transform 0.1s;
|
||||
}
|
||||
.btn-action:hover { opacity: 0.85; transform: translateY(-1px); text-decoration: none; }
|
||||
.btn-action:active { transform: translateY(0); }
|
||||
.btn-action.info { background: #eaf0fb; color: #1a4e8e; }
|
||||
.btn-action.warn { background: #fdf8ea; color: #8a6000; }
|
||||
.btn-action.danger { background: #fdf0f0; color: #c53030; }
|
||||
.btn-action.success { background: #d1fae5; color: #064e3b; }
|
||||
|
||||
/* ── TANGGAPAN FORM ── */
|
||||
.tanggapan-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
min-width: 180px;
|
||||
}
|
||||
.tanggapan-form textarea {
|
||||
border-radius: 9px !important;
|
||||
border: 1.5px solid #e0ede0 !important;
|
||||
font-size: 12px !important;
|
||||
padding: 7px 10px !important;
|
||||
resize: none;
|
||||
font-family: 'Plus Jakarta Sans', sans-serif;
|
||||
outline: none;
|
||||
transition: border-color 0.15s;
|
||||
}
|
||||
.tanggapan-form textarea:focus {
|
||||
border-color: #1a6e3a !important;
|
||||
box-shadow: 0 0 0 3px rgba(26,110,58,0.1);
|
||||
}
|
||||
|
||||
/* ── FOTO ── */
|
||||
.bukti-img {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: 8px;
|
||||
object-fit: cover;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.12);
|
||||
cursor: pointer;
|
||||
transition: transform 0.15s;
|
||||
}
|
||||
.bukti-img:hover { transform: scale(1.1); }
|
||||
|
||||
/* ── DESKRIPSI TRUNCATE ── */
|
||||
.desc-text {
|
||||
max-width: 200px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* ── MOBILE RESPONSIVE ── */
|
||||
.table-responsive-wrapper {
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.premium-table {
|
||||
min-width: 750px;
|
||||
}
|
||||
.page-header h1 { font-size: 18px; }
|
||||
.desc-text { max-width: 140px; }
|
||||
}
|
||||
|
||||
/* ── DATATABLES ── */
|
||||
.dataTables_wrapper { padding: 0; }
|
||||
.dataTables_wrapper .dataTables_length label,
|
||||
.dataTables_wrapper .dataTables_filter label {
|
||||
font-size: 13px;
|
||||
color: #5a6e5a;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin: 0;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_filter input {
|
||||
border-radius: 9px;
|
||||
border: 1.5px solid #e0ede0;
|
||||
padding: 6px 12px;
|
||||
font-size: 13px;
|
||||
outline: none;
|
||||
margin-left: 6px;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_filter input:focus {
|
||||
border-color: #1a6e3a;
|
||||
box-shadow: 0 0 0 3px rgba(26,110,58,0.12);
|
||||
}
|
||||
.dataTables_wrapper .dataTables_length select {
|
||||
border-radius: 9px;
|
||||
border: 1.5px solid #e0ede0;
|
||||
padding: 5px 10px;
|
||||
font-size: 13px;
|
||||
margin: 0 6px;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_info {
|
||||
font-size: 12.5px;
|
||||
color: #8a9e8a;
|
||||
font-weight: 500;
|
||||
padding: 0;
|
||||
line-height: 36px;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate {
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
gap: 3px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button {
|
||||
box-sizing: border-box !important;
|
||||
width: 34px !important;
|
||||
height: 34px !important;
|
||||
min-width: 34px !important;
|
||||
border-radius: 50% !important;
|
||||
padding: 0 !important;
|
||||
margin: 0 2px !important;
|
||||
font-size: 13px !important;
|
||||
font-weight: 600 !important;
|
||||
border: 1.5px solid #e0ede0 !important;
|
||||
color: #5a6e5a !important;
|
||||
background: #ffffff !important;
|
||||
display: inline-flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
line-height: 1 !important;
|
||||
cursor: pointer !important;
|
||||
text-decoration: none !important;
|
||||
transition: all 0.15s ease !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button:hover:not(.disabled):not(.current) {
|
||||
background: #eaf7f0 !important;
|
||||
border-color: #2e9e58 !important;
|
||||
color: #1a6e3a !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button.current,
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button.current:hover {
|
||||
background: #ffffff !important;
|
||||
border: 2px solid #1a6e3a !important;
|
||||
color: #1a6e3a !important;
|
||||
box-shadow: 0 0 0 3px rgba(26,110,58,0.12) !important;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button.disabled,
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button.disabled:hover {
|
||||
color: #c8d8c8 !important;
|
||||
border-color: #edf5ed !important;
|
||||
background: #fafafa !important;
|
||||
cursor: default !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container-fluid">
|
||||
|
||||
{{-- PAGE HEADER --}}
|
||||
<div class="page-header">
|
||||
<div class="page-header-icon">
|
||||
<i class="fas fa-headset"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h1>Layanan Pengaduan</h1>
|
||||
<p>Manajemen pengaduan dan tanggapan penghuni</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if(session('success'))
|
||||
<div class="alert-success-custom">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- TABEL PENGADUAN --}}
|
||||
<div class="premium-card">
|
||||
<div class="premium-card-header">
|
||||
<div class="header-left">
|
||||
<div class="header-icon green"><i class="fas fa-clipboard-list"></i></div>
|
||||
<h6>Daftar Pengaduan</h6>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="premium-card-body" style="padding: 0;">
|
||||
<table class="premium-table" id="dataTable" style="width:100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Nama</th>
|
||||
<th>Tanggal</th>
|
||||
<th>Kategori</th>
|
||||
<th>Deskripsi</th>
|
||||
<th>Foto</th>
|
||||
<th>Status</th>
|
||||
<th>Tanggapan</th>
|
||||
<th>Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($layanan as $item)
|
||||
<tr>
|
||||
<td>{{ $loop->iteration }}</td>
|
||||
|
||||
<td><strong>{{ $item->penghuni->nama ?? '-' }}</strong></td>
|
||||
|
||||
<td style="white-space:nowrap;">
|
||||
{{ \Carbon\Carbon::parse($item->tanggal_pengaduan)->translatedFormat('d M Y') }}
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<span class="badge-pill-custom badge-blue">
|
||||
<i class="fas fa-tag" style="font-size:9px"></i>
|
||||
{{ ucfirst($item->kategori_masalah) }}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<span class="desc-text" title="{{ $item->deskripsi }}">
|
||||
{{ \Illuminate\Support\Str::limit($item->deskripsi, 45) }}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
@if($item->foto)
|
||||
<img src="{{ asset('storage/' . $item->foto) }}" class="bukti-img">
|
||||
@else
|
||||
<span style="color:#ccc; font-size:12px;">—</span>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td>
|
||||
@if($item->status == 'diajukan')
|
||||
<span class="badge-pill-custom badge-yellow"><i class="fas fa-paper-plane" style="font-size:9px"></i> Diajukan</span>
|
||||
@elseif($item->status == 'menunggu')
|
||||
<span class="badge-pill-custom badge-blue"><i class="fas fa-hourglass-half" style="font-size:9px"></i> Menunggu</span>
|
||||
@elseif($item->status == 'selesai')
|
||||
<span class="badge-pill-custom badge-green"><i class="fas fa-check-circle" style="font-size:9px"></i> Selesai</span>
|
||||
@else
|
||||
<span class="badge-pill-custom badge-gray"><i class="fas fa-question-circle" style="font-size:9px"></i> Unknown</span>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td style="max-width: 180px;">
|
||||
@if($item->tanggapan_admin)
|
||||
<span class="desc-text" title="{{ $item->tanggapan_admin }}">
|
||||
{{ \Illuminate\Support\Str::limit($item->tanggapan_admin, 40) }}
|
||||
</span>
|
||||
@else
|
||||
<span style="color:#ccc; font-size:12px; font-style:italic;">Belum ada tanggapan</span>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td style="white-space:nowrap; min-width:160px;">
|
||||
{{-- RT: Tanggapi --}}
|
||||
@if(auth()->user()->role == 'rt' && $item->status == 'diajukan')
|
||||
<form action="{{ route('layanan.tanggapi.rt', $item->id) }}" method="POST">
|
||||
@csrf
|
||||
<div class="tanggapan-form">
|
||||
<textarea name="tanggapan_admin" rows="2" placeholder="Tulis tanggapan..." required></textarea>
|
||||
<button type="submit" class="btn-action success">
|
||||
<i class="fas fa-reply" style="font-size:10px"></i> Tanggapi
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@endif
|
||||
|
||||
{{-- ADMIN: Approve --}}
|
||||
@if(auth()->user()->role == 'admin' && $item->status == 'menunggu')
|
||||
<form action="{{ route('layanan.approve.admin', $item->id) }}" method="POST" style="display:inline;">
|
||||
@csrf
|
||||
<button class="btn-action success">
|
||||
<i class="fas fa-check-double" style="font-size:10px"></i> Approve
|
||||
</button>
|
||||
</form>
|
||||
@endif
|
||||
|
||||
{{-- HAPUS --}}
|
||||
<form action="{{ route('layanan.delete', $item->id) }}" method="POST" style="display:inline;">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button class="btn-action danger" onclick="return confirm('Yakin hapus pengaduan ini?')">
|
||||
<i class="fas fa-trash" style="font-size:10px"></i> Hapus
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="9" style="text-align:center; padding: 32px; color: #aaa;">
|
||||
<i class="fas fa-inbox" style="font-size:28px; display:block; margin-bottom:8px; opacity:0.4;"></i>
|
||||
Belum ada data pengaduan
|
||||
</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
if ($.fn.DataTable) {
|
||||
$('#dataTable').DataTable({
|
||||
pageLength: 10,
|
||||
lengthMenu: [5, 10, 25, 50],
|
||||
dom: '<"d-flex justify-content-between align-items-center px-3 pt-3"lf>t<"d-flex justify-content-between align-items-center px-3 pb-3"ip>',
|
||||
language: {
|
||||
search: "Cari:",
|
||||
lengthMenu: "Tampilkan _MENU_ data",
|
||||
info: "Menampilkan _START_–_END_ dari _TOTAL_ data",
|
||||
infoEmpty: "Tidak ada data",
|
||||
paginate: {
|
||||
first: "«",
|
||||
last: "»",
|
||||
next: "›",
|
||||
previous: "‹"
|
||||
},
|
||||
emptyTable: "Belum ada data pengaduan"
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
|
|
@ -0,0 +1,491 @@
|
|||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
*, *::before, *::after { box-sizing: border-box; }
|
||||
body { font-family: 'Plus Jakarta Sans', sans-serif; }
|
||||
|
||||
/* ── PAGE HEADER ── */
|
||||
.page-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
.page-header-icon {
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
background: linear-gradient(135deg, #064e3b, #0d6e4f);
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
font-size: 20px;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0 4px 14px rgba(6,78,59,0.3);
|
||||
}
|
||||
.page-header h1 {
|
||||
font-size: 22px;
|
||||
font-weight: 800;
|
||||
color: #1a2e1a;
|
||||
margin: 0;
|
||||
line-height: 1.2;
|
||||
}
|
||||
.page-header p {
|
||||
font-size: 13px;
|
||||
color: #8a9e8a;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ── ALERT ── */
|
||||
.alert-success-custom {
|
||||
background: #f0faf4;
|
||||
border: 1px solid #a8e6be;
|
||||
border-left: 4px solid #1a6e3a;
|
||||
border-radius: 12px;
|
||||
padding: 12px 16px;
|
||||
color: #1a4e2a;
|
||||
font-size: 13.5px;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
/* ── CARD ── */
|
||||
.premium-card {
|
||||
background: #ffffff;
|
||||
border-radius: 16px;
|
||||
border: 1px solid #e8f0e8;
|
||||
box-shadow: 0 2px 12px rgba(0,0,0,0.05);
|
||||
margin-bottom: 24px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.premium-card-header {
|
||||
padding: 16px 22px;
|
||||
background: #ffffff;
|
||||
border-bottom: 1px solid #f0f5f0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.premium-card-header .header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
.header-icon {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
border-radius: 9px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 15px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.header-icon.green { background: #d1fae5; color: #064e3b; }
|
||||
.premium-card-header h6 {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: #1a2e1a;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ── TABLE ── */
|
||||
.premium-table {
|
||||
width: 100%;
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
font-size: 13px;
|
||||
}
|
||||
.premium-table thead tr th {
|
||||
background: #f6fbf7;
|
||||
color: #3a5a3a;
|
||||
font-weight: 700;
|
||||
font-size: 11.5px;
|
||||
letter-spacing: 0.5px;
|
||||
text-transform: uppercase;
|
||||
padding: 11px 14px;
|
||||
border-bottom: 2px solid #e0ede0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.premium-table thead tr th:first-child { border-radius: 10px 0 0 0; }
|
||||
.premium-table thead tr th:last-child { border-radius: 0 10px 0 0; }
|
||||
.premium-table tbody tr td {
|
||||
padding: 11px 14px;
|
||||
border-bottom: 1px solid #f2f7f2;
|
||||
color: #2a3a2a;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.premium-table tbody tr:hover td { background: #f8fdf8; }
|
||||
.premium-table tbody tr:last-child td { border-bottom: none; }
|
||||
|
||||
/* ── BADGES ── */
|
||||
.badge-pill-custom {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 99px;
|
||||
font-size: 11.5px;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.badge-green { background: #d1fae5; color: #064e3b; }
|
||||
.badge-red { background: #fdf0f0; color: #c53030; }
|
||||
.badge-yellow { background: #fdfbea; color: #7a6010; }
|
||||
.badge-blue { background: #eaf0fb; color: #1a4e8e; }
|
||||
.badge-gray { background: #f3f4f6; color: #4b5563; }
|
||||
|
||||
/* ── ACTION BUTTONS ── */
|
||||
.btn-action {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
padding: 5px 11px;
|
||||
border-radius: 8px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
text-decoration: none;
|
||||
transition: opacity 0.15s, transform 0.1s;
|
||||
}
|
||||
.btn-action:hover { opacity: 0.85; transform: translateY(-1px); text-decoration: none; }
|
||||
.btn-action:active { transform: translateY(0); }
|
||||
.btn-action.info { background: #eaf0fb; color: #1a4e8e; }
|
||||
.btn-action.warn { background: #fdf8ea; color: #8a6000; }
|
||||
.btn-action.danger { background: #fdf0f0; color: #c53030; }
|
||||
.btn-action.success { background: #d1fae5; color: #064e3b; }
|
||||
|
||||
/* ── TANGGAPAN FORM ── */
|
||||
.tanggapan-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
min-width: 180px;
|
||||
}
|
||||
.tanggapan-form textarea {
|
||||
border-radius: 9px !important;
|
||||
border: 1.5px solid #e0ede0 !important;
|
||||
font-size: 12px !important;
|
||||
padding: 7px 10px !important;
|
||||
resize: none;
|
||||
font-family: 'Plus Jakarta Sans', sans-serif;
|
||||
outline: none;
|
||||
transition: border-color 0.15s;
|
||||
}
|
||||
.tanggapan-form textarea:focus {
|
||||
border-color: #1a6e3a !important;
|
||||
box-shadow: 0 0 0 3px rgba(26,110,58,0.1);
|
||||
}
|
||||
|
||||
/* ── FOTO ── */
|
||||
.bukti-img {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: 8px;
|
||||
object-fit: cover;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.12);
|
||||
cursor: pointer;
|
||||
transition: transform 0.15s;
|
||||
}
|
||||
.bukti-img:hover { transform: scale(1.1); }
|
||||
|
||||
/* ── DESKRIPSI TRUNCATE ── */
|
||||
.desc-text {
|
||||
max-width: 200px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* ── MOBILE RESPONSIVE ── */
|
||||
.table-responsive-wrapper {
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.premium-table {
|
||||
min-width: 750px;
|
||||
}
|
||||
.page-header h1 { font-size: 18px; }
|
||||
.desc-text { max-width: 140px; }
|
||||
}
|
||||
|
||||
/* ── DATATABLES ── */
|
||||
.dataTables_wrapper { padding: 0; }
|
||||
.dataTables_wrapper .dataTables_length label,
|
||||
.dataTables_wrapper .dataTables_filter label {
|
||||
font-size: 13px;
|
||||
color: #5a6e5a;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin: 0;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_filter input {
|
||||
border-radius: 9px;
|
||||
border: 1.5px solid #e0ede0;
|
||||
padding: 6px 12px;
|
||||
font-size: 13px;
|
||||
outline: none;
|
||||
margin-left: 6px;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_filter input:focus {
|
||||
border-color: #1a6e3a;
|
||||
box-shadow: 0 0 0 3px rgba(26,110,58,0.12);
|
||||
}
|
||||
.dataTables_wrapper .dataTables_length select {
|
||||
border-radius: 9px;
|
||||
border: 1.5px solid #e0ede0;
|
||||
padding: 5px 10px;
|
||||
font-size: 13px;
|
||||
margin: 0 6px;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_info {
|
||||
font-size: 12.5px;
|
||||
color: #8a9e8a;
|
||||
font-weight: 500;
|
||||
padding: 0;
|
||||
line-height: 36px;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate {
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
gap: 3px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button {
|
||||
box-sizing: border-box !important;
|
||||
width: 34px !important;
|
||||
height: 34px !important;
|
||||
min-width: 34px !important;
|
||||
border-radius: 50% !important;
|
||||
padding: 0 !important;
|
||||
margin: 0 2px !important;
|
||||
font-size: 13px !important;
|
||||
font-weight: 600 !important;
|
||||
border: 1.5px solid #e0ede0 !important;
|
||||
color: #5a6e5a !important;
|
||||
background: #ffffff !important;
|
||||
display: inline-flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
line-height: 1 !important;
|
||||
cursor: pointer !important;
|
||||
text-decoration: none !important;
|
||||
transition: all 0.15s ease !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button:hover:not(.disabled):not(.current) {
|
||||
background: #eaf7f0 !important;
|
||||
border-color: #2e9e58 !important;
|
||||
color: #1a6e3a !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button.current,
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button.current:hover {
|
||||
background: #ffffff !important;
|
||||
border: 2px solid #1a6e3a !important;
|
||||
color: #1a6e3a !important;
|
||||
box-shadow: 0 0 0 3px rgba(26,110,58,0.12) !important;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button.disabled,
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button.disabled:hover {
|
||||
color: #c8d8c8 !important;
|
||||
border-color: #edf5ed !important;
|
||||
background: #fafafa !important;
|
||||
cursor: default !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container-fluid">
|
||||
|
||||
{{-- PAGE HEADER --}}
|
||||
<div class="page-header">
|
||||
<div class="page-header-icon">
|
||||
<i class="fas fa-headset"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h1>Layanan Pengaduan</h1>
|
||||
<p>Manajemen pengaduan dan tanggapan penghuni</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if(session('success'))
|
||||
<div class="alert-success-custom">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- TABEL PENGADUAN --}}
|
||||
<div class="premium-card">
|
||||
<div class="premium-card-header">
|
||||
<div class="header-left">
|
||||
<div class="header-icon green"><i class="fas fa-clipboard-list"></i></div>
|
||||
<h6>Daftar Pengaduan</h6>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="premium-card-body" style="padding: 0;">
|
||||
<div class="table-responsive-wrapper">
|
||||
<table class="premium-table" id="dataTable" style="width:100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Nama</th>
|
||||
<th>Tanggal</th>
|
||||
<th>Kategori</th>
|
||||
<th>Deskripsi</th>
|
||||
<th>Foto</th>
|
||||
<th>Status</th>
|
||||
<th>Tanggapan</th>
|
||||
<th>Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($layanan as $item)
|
||||
<tr>
|
||||
<td>{{ $loop->iteration }}</td>
|
||||
|
||||
<td><strong>{{ $item->penghuni->nama ?? '-' }}</strong></td>
|
||||
|
||||
<td style="white-space:nowrap;">
|
||||
{{ \Carbon\Carbon::parse($item->tanggal_pengaduan)->translatedFormat('d M Y') }}
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<span class="badge-pill-custom badge-blue">
|
||||
<i class="fas fa-tag" style="font-size:9px"></i>
|
||||
{{ ucfirst($item->kategori_masalah) }}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<span class="desc-text" title="{{ $item->deskripsi }}">
|
||||
{{ \Illuminate\Support\Str::limit($item->deskripsi, 45) }}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
@if($item->foto)
|
||||
<img src="{{ asset('storage/' . $item->foto) }}" class="bukti-img">
|
||||
@else
|
||||
<span style="color:#ccc; font-size:12px;">—</span>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td>
|
||||
@if($item->status == 'diajukan')
|
||||
<span class="badge-pill-custom badge-yellow"><i class="fas fa-paper-plane" style="font-size:9px"></i> Diajukan</span>
|
||||
@elseif($item->status == 'menunggu')
|
||||
<span class="badge-pill-custom badge-blue"><i class="fas fa-hourglass-half" style="font-size:9px"></i> Menunggu</span>
|
||||
@elseif($item->status == 'selesai')
|
||||
<span class="badge-pill-custom badge-green"><i class="fas fa-check-circle" style="font-size:9px"></i> Selesai</span>
|
||||
@else
|
||||
<span class="badge-pill-custom badge-gray"><i class="fas fa-question-circle" style="font-size:9px"></i> Unknown</span>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td style="max-width: 180px;">
|
||||
@if($item->tanggapan_admin)
|
||||
<span class="desc-text" title="{{ $item->tanggapan_admin }}">
|
||||
{{ \Illuminate\Support\Str::limit($item->tanggapan_admin, 40) }}
|
||||
</span>
|
||||
@else
|
||||
<span style="color:#ccc; font-size:12px; font-style:italic;">Belum ada tanggapan</span>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td style="white-space:nowrap; min-width:160px;">
|
||||
{{-- RT: Tanggapi --}}
|
||||
@if(auth()->user()->role == 'rt' && $item->status == 'diajukan')
|
||||
<form action="{{ route('layanan.tanggapi.rt', $item->id) }}" method="POST">
|
||||
@csrf
|
||||
<div class="tanggapan-form">
|
||||
<textarea name="tanggapan_admin" rows="2" placeholder="Tulis tanggapan..." required></textarea>
|
||||
<button type="submit" class="btn-action success">
|
||||
<i class="fas fa-reply" style="font-size:10px"></i> Tanggapi
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@endif
|
||||
|
||||
{{-- ADMIN: Approve --}}
|
||||
@if(auth()->user()->role == 'admin' && $item->status == 'menunggu')
|
||||
<form action="{{ route('layanan.approve.admin', $item->id) }}" method="POST" style="display:inline;">
|
||||
@csrf
|
||||
<button class="btn-action success">
|
||||
<i class="fas fa-check-double" style="font-size:10px"></i> Approve
|
||||
</button>
|
||||
</form>
|
||||
@endif
|
||||
|
||||
{{-- HAPUS --}}
|
||||
<form action="{{ route('layanan.delete', $item->id) }}" method="POST" style="display:inline;">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button class="btn-action danger" onclick="return confirm('Yakin hapus pengaduan ini?')">
|
||||
<i class="fas fa-trash" style="font-size:10px"></i> Hapus
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="9" style="text-align:center; padding: 32px; color: #aaa;">
|
||||
<i class="fas fa-inbox" style="font-size:28px; display:block; margin-bottom:8px; opacity:0.4;"></i>
|
||||
Belum ada data pengaduan
|
||||
</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
if ($.fn.DataTable) {
|
||||
$('#dataTable').DataTable({
|
||||
pageLength: 10,
|
||||
lengthMenu: [5, 10, 25, 50],
|
||||
dom: '<"d-flex justify-content-between align-items-center px-3 pt-3"lf>t<"d-flex justify-content-between align-items-center px-3 pb-3"ip>',
|
||||
language: {
|
||||
search: "Cari:",
|
||||
lengthMenu: "Tampilkan _MENU_ data",
|
||||
info: "Menampilkan _START_–_END_ dari _TOTAL_ data",
|
||||
infoEmpty: "Tidak ada data",
|
||||
paginate: {
|
||||
first: "«",
|
||||
last: "»",
|
||||
next: "›",
|
||||
previous: "‹"
|
||||
},
|
||||
emptyTable: "Belum ada data pengaduan"
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
|
|
@ -0,0 +1,491 @@
|
|||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
*, *::before, *::after { box-sizing: border-box; }
|
||||
body { font-family: 'Plus Jakarta Sans', sans-serif; }
|
||||
|
||||
/* ── PAGE HEADER ── */
|
||||
.page-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
.page-header-icon {
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
background: linear-gradient(135deg, #064e3b, #0d6e4f);
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
font-size: 20px;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0 4px 14px rgba(6,78,59,0.3);
|
||||
}
|
||||
.page-header h1 {
|
||||
font-size: 22px;
|
||||
font-weight: 800;
|
||||
color: #1a2e1a;
|
||||
margin: 0;
|
||||
line-height: 1.2;
|
||||
}
|
||||
.page-header p {
|
||||
font-size: 13px;
|
||||
color: #8a9e8a;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ── ALERT ── */
|
||||
.alert-success-custom {
|
||||
background: #f0faf4;
|
||||
border: 1px solid #a8e6be;
|
||||
border-left: 4px solid #1a6e3a;
|
||||
border-radius: 12px;
|
||||
padding: 12px 16px;
|
||||
color: #1a4e2a;
|
||||
font-size: 13.5px;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
/* ── CARD ── */
|
||||
.premium-card {
|
||||
background: #ffffff;
|
||||
border-radius: 16px;
|
||||
border: 1px solid #e8f0e8;
|
||||
box-shadow: 0 2px 12px rgba(0,0,0,0.05);
|
||||
margin-bottom: 24px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.premium-card-header {
|
||||
padding: 16px 22px;
|
||||
background: #ffffff;
|
||||
border-bottom: 1px solid #f0f5f0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.premium-card-header .header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
.header-icon {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
border-radius: 9px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 15px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.header-icon.green { background: #d1fae5; color: #064e3b; }
|
||||
.premium-card-header h6 {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: #1a2e1a;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ── TABLE ── */
|
||||
.premium-table {
|
||||
width: 100%;
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
font-size: 13px;
|
||||
}
|
||||
.premium-table thead tr th {
|
||||
background: #f6fbf7;
|
||||
color: #3a5a3a;
|
||||
font-weight: 700;
|
||||
font-size: 11.5px;
|
||||
letter-spacing: 0.5px;
|
||||
text-transform: uppercase;
|
||||
padding: 11px 14px;
|
||||
border-bottom: 2px solid #e0ede0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.premium-table thead tr th:first-child { border-radius: 10px 0 0 0; }
|
||||
.premium-table thead tr th:last-child { border-radius: 0 10px 0 0; }
|
||||
.premium-table tbody tr td {
|
||||
padding: 11px 14px;
|
||||
border-bottom: 1px solid #f2f7f2;
|
||||
color: #2a3a2a;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.premium-table tbody tr:hover td { background: #f8fdf8; }
|
||||
.premium-table tbody tr:last-child td { border-bottom: none; }
|
||||
|
||||
/* ── BADGES ── */
|
||||
.badge-pill-custom {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 99px;
|
||||
font-size: 11.5px;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.badge-green { background: #d1fae5; color: #064e3b; }
|
||||
.badge-red { background: #fdf0f0; color: #c53030; }
|
||||
.badge-yellow { background: #fdfbea; color: #7a6010; }
|
||||
.badge-blue { background: #eaf0fb; color: #1a4e8e; }
|
||||
.badge-gray { background: #f3f4f6; color: #4b5563; }
|
||||
|
||||
/* ── ACTION BUTTONS ── */
|
||||
.btn-action {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
padding: 5px 11px;
|
||||
border-radius: 8px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
text-decoration: none;
|
||||
transition: opacity 0.15s, transform 0.1s;
|
||||
}
|
||||
.btn-action:hover { opacity: 0.85; transform: translateY(-1px); text-decoration: none; }
|
||||
.btn-action:active { transform: translateY(0); }
|
||||
.btn-action.info { background: #eaf0fb; color: #1a4e8e; }
|
||||
.btn-action.warn { background: #fdf8ea; color: #8a6000; }
|
||||
.btn-action.danger { background: #fdf0f0; color: #c53030; }
|
||||
.btn-action.success { background: #d1fae5; color: #064e3b; }
|
||||
|
||||
/* ── TANGGAPAN FORM ── */
|
||||
.tanggapan-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
min-width: 180px;
|
||||
}
|
||||
.tanggapan-form textarea {
|
||||
border-radius: 9px !important;
|
||||
border: 1.5px solid #e0ede0 !important;
|
||||
font-size: 12px !important;
|
||||
padding: 7px 10px !important;
|
||||
resize: none;
|
||||
font-family: 'Plus Jakarta Sans', sans-serif;
|
||||
outline: none;
|
||||
transition: border-color 0.15s;
|
||||
}
|
||||
.tanggapan-form textarea:focus {
|
||||
border-color: #1a6e3a !important;
|
||||
box-shadow: 0 0 0 3px rgba(26,110,58,0.1);
|
||||
}
|
||||
|
||||
/* ── FOTO ── */
|
||||
.bukti-img {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: 8px;
|
||||
object-fit: cover;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.12);
|
||||
cursor: pointer;
|
||||
transition: transform 0.15s;
|
||||
}
|
||||
.bukti-img:hover { transform: scale(1.1); }
|
||||
|
||||
/* ── DESKRIPSI TRUNCATE ── */
|
||||
.desc-text {
|
||||
max-width: 200px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* ── MOBILE RESPONSIVE ── */
|
||||
.table-responsive-wrapper {
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.premium-table {
|
||||
min-width: 750px;
|
||||
}
|
||||
.page-header h1 { font-size: 18px; }
|
||||
.desc-text { max-width: 140px; }
|
||||
}
|
||||
|
||||
/* ── DATATABLES ── */
|
||||
.dataTables_wrapper { padding: 0; }
|
||||
.dataTables_wrapper .dataTables_length label,
|
||||
.dataTables_wrapper .dataTables_filter label {
|
||||
font-size: 13px;
|
||||
color: #5a6e5a;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin: 0;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_filter input {
|
||||
border-radius: 9px;
|
||||
border: 1.5px solid #e0ede0;
|
||||
padding: 6px 12px;
|
||||
font-size: 13px;
|
||||
outline: none;
|
||||
margin-left: 6px;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_filter input:focus {
|
||||
border-color: #1a6e3a;
|
||||
box-shadow: 0 0 0 3px rgba(26,110,58,0.12);
|
||||
}
|
||||
.dataTables_wrapper .dataTables_length select {
|
||||
border-radius: 9px;
|
||||
border: 1.5px solid #e0ede0;
|
||||
padding: 5px 10px;
|
||||
font-size: 13px;
|
||||
margin: 0 6px;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_info {
|
||||
font-size: 12.5px;
|
||||
color: #8a9e8a;
|
||||
font-weight: 500;
|
||||
padding: 0;
|
||||
line-height: 36px;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate {
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
gap: 3px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button {
|
||||
box-sizing: border-box !important;
|
||||
width: 34px !important;
|
||||
height: 34px !important;
|
||||
min-width: 34px !important;
|
||||
border-radius: 50% !important;
|
||||
padding: 0 !important;
|
||||
margin: 0 2px !important;
|
||||
font-size: 13px !important;
|
||||
font-weight: 600 !important;
|
||||
border: 1.5px solid #e0ede0 !important;
|
||||
color: #5a6e5a !important;
|
||||
background: #ffffff !important;
|
||||
display: inline-flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
line-height: 1 !important;
|
||||
cursor: pointer !important;
|
||||
text-decoration: none !important;
|
||||
transition: all 0.15s ease !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button:hover:not(.disabled):not(.current) {
|
||||
background: #eaf7f0 !important;
|
||||
border-color: #2e9e58 !important;
|
||||
color: #1a6e3a !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button.current,
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button.current:hover {
|
||||
background: #ffffff !important;
|
||||
border: 2px solid #1a6e3a !important;
|
||||
color: #1a6e3a !important;
|
||||
box-shadow: 0 0 0 3px rgba(26,110,58,0.12) !important;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button.disabled,
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button.disabled:hover {
|
||||
color: #c8d8c8 !important;
|
||||
border-color: #edf5ed !important;
|
||||
background: #fafafa !important;
|
||||
cursor: default !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container-fluid">
|
||||
|
||||
{{-- PAGE HEADER --}}
|
||||
<div class="page-header">
|
||||
<div class="page-header-icon">
|
||||
<i class="fas fa-headset"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h1>Layanan Pengaduan</h1>
|
||||
<p>Manajemen pengaduan dan tanggapan penghuni</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if(session('success'))
|
||||
<div class="alert-success-custom">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- TABEL PENGADUAN --}}
|
||||
<div class="premium-card">
|
||||
<div class="premium-card-header">
|
||||
<div class="header-left">
|
||||
<div class="header-icon green"><i class="fas fa-clipboard-list"></i></div>
|
||||
<h6>Daftar Pengaduan</h6>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="premium-card-body" style="padding: 0;">
|
||||
<div class="table-responsive-wrapper">
|
||||
<table class="premium-table" id="dataTable" style="width:100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Nama</th>
|
||||
<th>Tanggal</th>
|
||||
<th>Kategori</th>
|
||||
<th>Deskripsi</th>
|
||||
<th>Foto</th>
|
||||
<th>Status</th>
|
||||
<th>Tanggapan</th>
|
||||
<th>Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($layanan as $item)
|
||||
<tr>
|
||||
<td>{{ $loop->iteration }}</td>
|
||||
|
||||
<td><strong>{{ $item->penghuni->nama ?? '-' }}</strong></td>
|
||||
|
||||
<td style="white-space:nowrap;">
|
||||
{{ \Carbon\Carbon::parse($item->tanggal_pengaduan)->translatedFormat('d M Y') }}
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<span class="badge-pill-custom badge-blue">
|
||||
<i class="fas fa-tag" style="font-size:9px"></i>
|
||||
{{ ucfirst($item->kategori_masalah) }}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<span class="desc-text" title="{{ $item->deskripsi }}">
|
||||
{{ \Illuminate\Support\Str::limit($item->deskripsi, 45) }}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
@if($item->foto)
|
||||
<img src="{{ asset('storage/' . $item->foto) }}" class="bukti-img">
|
||||
@else
|
||||
<span style="color:#ccc; font-size:12px;">—</span>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td>
|
||||
@if($item->status == 'diajukan')
|
||||
<span class="badge-pill-custom badge-yellow"><i class="fas fa-paper-plane" style="font-size:9px"></i> Diajukan</span>
|
||||
@elseif($item->status == 'menunggu')
|
||||
<span class="badge-pill-custom badge-blue"><i class="fas fa-hourglass-half" style="font-size:9px"></i> Menunggu</span>
|
||||
@elseif($item->status == 'selesai')
|
||||
<span class="badge-pill-custom badge-green"><i class="fas fa-check-circle" style="font-size:9px"></i> Selesai</span>
|
||||
@else
|
||||
<span class="badge-pill-custom badge-gray"><i class="fas fa-question-circle" style="font-size:9px"></i> Unknown</span>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td style="max-width: 180px;">
|
||||
@if($item->tanggapan_admin)
|
||||
<span class="desc-text" title="{{ $item->tanggapan_admin }}">
|
||||
{{ \Illuminate\Support\Str::limit($item->tanggapan_admin, 40) }}
|
||||
</span>
|
||||
@else
|
||||
<span style="color:#ccc; font-size:12px; font-style:italic;">Belum ada tanggapan</span>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td style="white-space:nowrap; min-width:160px;">
|
||||
{{-- RT: Tanggapi --}}
|
||||
@if(auth()->user()->role == 'rt' && $item->status == 'diajukan')
|
||||
<form action="{{ route('layanan.tanggapi.rt', $item->id) }}" method="POST">
|
||||
@csrf
|
||||
<div class="tanggapan-form">
|
||||
<textarea name="tanggapan_admin" rows="2" placeholder="Tulis tanggapan..." required></textarea>
|
||||
<button type="submit" class="btn-action success">
|
||||
<i class="fas fa-reply" style="font-size:10px"></i> Tanggapi
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@endif
|
||||
|
||||
{{-- ADMIN: Approve --}}
|
||||
@if(auth()->user()->role == 'admin' && $item->status == 'menunggu')
|
||||
<form action="{{ route('layanan.approve.admin', $item->id) }}" method="POST" style="display:inline;">
|
||||
@csrf
|
||||
<button class="btn-action success">
|
||||
<i class="fas fa-check-double" style="font-size:10px"></i> Approve
|
||||
</button>
|
||||
</form>
|
||||
@endif
|
||||
|
||||
{{-- HAPUS --}}
|
||||
<form action="{{ route('layanan.delete', $item->id) }}" method="POST" style="display:inline;">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button class="btn-action danger" onclick="return confirm('Yakin hapus pengaduan ini?')">
|
||||
<i class="fas fa-trash" style="font-size:10px"></i> Hapus
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="9" style="text-align:center; padding: 32px; color: #aaa;">
|
||||
<i class="fas fa-inbox" style="font-size:28px; display:block; margin-bottom:8px; opacity:0.4;"></i>
|
||||
Belum ada data pengaduan
|
||||
</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
if ($.fn.DataTable) {
|
||||
$('#dataTable').DataTable({
|
||||
pageLength: 10,
|
||||
lengthMenu: [5, 10, 25, 50],
|
||||
dom: '<"d-flex justify-content-between align-items-center px-3 pt-3"lf>t<"d-flex justify-content-between align-items-center px-3 pb-3"ip>',
|
||||
language: {
|
||||
search: "Cari:",
|
||||
lengthMenu: "Tampilkan _MENU_ data",
|
||||
info: "Menampilkan _START_–_END_ dari _TOTAL_ data",
|
||||
infoEmpty: "Tidak ada data",
|
||||
paginate: {
|
||||
first: "«",
|
||||
last: "»",
|
||||
next: "›",
|
||||
previous: "‹"
|
||||
},
|
||||
emptyTable: "Belum ada data pengaduan"
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
|
|
@ -0,0 +1,492 @@
|
|||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
*, *::before, *::after { box-sizing: border-box; }
|
||||
body { font-family: 'Plus Jakarta Sans', sans-serif; }
|
||||
|
||||
/* ── PAGE HEADER ── */
|
||||
.page-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
.page-header-icon {
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
background: linear-gradient(135deg, #064e3b, #0d6e4f);
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
font-size: 20px;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0 4px 14px rgba(6,78,59,0.3);
|
||||
}
|
||||
.page-header h1 {
|
||||
font-size: 22px;
|
||||
font-weight: 800;
|
||||
color: #1a2e1a;
|
||||
margin: 0;
|
||||
line-height: 1.2;
|
||||
}
|
||||
.page-header p {
|
||||
font-size: 13px;
|
||||
color: #8a9e8a;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ── ALERT ── */
|
||||
.alert-success-custom {
|
||||
background: #f0faf4;
|
||||
border: 1px solid #a8e6be;
|
||||
border-left: 4px solid #1a6e3a;
|
||||
border-radius: 12px;
|
||||
padding: 12px 16px;
|
||||
color: #1a4e2a;
|
||||
font-size: 13.5px;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
/* ── CARD ── */
|
||||
.premium-card {
|
||||
background: #ffffff;
|
||||
border-radius: 16px;
|
||||
border: 1px solid #e8f0e8;
|
||||
box-shadow: 0 2px 12px rgba(0,0,0,0.05);
|
||||
margin-bottom: 24px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.premium-card-header {
|
||||
padding: 16px 22px;
|
||||
background: #ffffff;
|
||||
border-bottom: 1px solid #f0f5f0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.premium-card-header .header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
.header-icon {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
border-radius: 9px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 15px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.header-icon.green { background: #d1fae5; color: #064e3b; }
|
||||
.premium-card-header h6 {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: #1a2e1a;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ── TABLE ── */
|
||||
.premium-table {
|
||||
width: 100%;
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
font-size: 13px;
|
||||
}
|
||||
.premium-table thead tr th {
|
||||
background: #f6fbf7;
|
||||
color: #3a5a3a;
|
||||
font-weight: 700;
|
||||
font-size: 11.5px;
|
||||
letter-spacing: 0.5px;
|
||||
text-transform: uppercase;
|
||||
padding: 11px 14px;
|
||||
border-bottom: 2px solid #e0ede0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.premium-table thead tr th:first-child { border-radius: 10px 0 0 0; }
|
||||
.premium-table thead tr th:last-child { border-radius: 0 10px 0 0; }
|
||||
.premium-table tbody tr td {
|
||||
padding: 11px 14px;
|
||||
border-bottom: 1px solid #f2f7f2;
|
||||
color: #2a3a2a;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.premium-table tbody tr:hover td { background: #f8fdf8; }
|
||||
.premium-table tbody tr:last-child td { border-bottom: none; }
|
||||
|
||||
/* ── BADGES ── */
|
||||
.badge-pill-custom {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 99px;
|
||||
font-size: 11.5px;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.badge-green { background: #d1fae5; color: #064e3b; }
|
||||
.badge-red { background: #fdf0f0; color: #c53030; }
|
||||
.badge-yellow { background: #fdfbea; color: #7a6010; }
|
||||
.badge-blue { background: #eaf0fb; color: #1a4e8e; }
|
||||
.badge-gray { background: #f3f4f6; color: #4b5563; }
|
||||
|
||||
/* ── ACTION BUTTONS ── */
|
||||
.btn-action {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
padding: 5px 11px;
|
||||
border-radius: 8px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
text-decoration: none;
|
||||
transition: opacity 0.15s, transform 0.1s;
|
||||
}
|
||||
.btn-action:hover { opacity: 0.85; transform: translateY(-1px); text-decoration: none; }
|
||||
.btn-action:active { transform: translateY(0); }
|
||||
.btn-action.info { background: #eaf0fb; color: #1a4e8e; }
|
||||
.btn-action.warn { background: #fdf8ea; color: #8a6000; }
|
||||
.btn-action.danger { background: #fdf0f0; color: #c53030; }
|
||||
.btn-action.success { background: #d1fae5; color: #064e3b; }
|
||||
|
||||
/* ── TANGGAPAN FORM ── */
|
||||
.tanggapan-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
min-width: 180px;
|
||||
}
|
||||
.tanggapan-form textarea {
|
||||
border-radius: 9px !important;
|
||||
border: 1.5px solid #e0ede0 !important;
|
||||
font-size: 12px !important;
|
||||
padding: 7px 10px !important;
|
||||
resize: none;
|
||||
font-family: 'Plus Jakarta Sans', sans-serif;
|
||||
outline: none;
|
||||
transition: border-color 0.15s;
|
||||
}
|
||||
.tanggapan-form textarea:focus {
|
||||
border-color: #1a6e3a !important;
|
||||
box-shadow: 0 0 0 3px rgba(26,110,58,0.1);
|
||||
}
|
||||
|
||||
/* ── FOTO ── */
|
||||
.bukti-img {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: 8px;
|
||||
object-fit: cover;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.12);
|
||||
cursor: pointer;
|
||||
transition: transform 0.15s;
|
||||
}
|
||||
.bukti-img:hover { transform: scale(1.1); }
|
||||
|
||||
/* ── DESKRIPSI TRUNCATE ── */
|
||||
.desc-text {
|
||||
max-width: 200px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* ── MOBILE RESPONSIVE ── */
|
||||
.table-responsive-wrapper {
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.premium-table {
|
||||
min-width: 750px;
|
||||
}
|
||||
.page-header h1 { font-size: 18px; }
|
||||
.desc-text { max-width: 140px; }
|
||||
}
|
||||
|
||||
/* ── DATATABLES ── */
|
||||
.dataTables_wrapper { padding: 0; }
|
||||
.dataTables_wrapper .dataTables_length label,
|
||||
.dataTables_wrapper .dataTables_filter label {
|
||||
font-size: 13px;
|
||||
color: #5a6e5a;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin: 0;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_filter input {
|
||||
border-radius: 9px;
|
||||
border: 1.5px solid #e0ede0;
|
||||
padding: 6px 12px;
|
||||
font-size: 13px;
|
||||
outline: none;
|
||||
margin-left: 6px;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_filter input:focus {
|
||||
border-color: #1a6e3a;
|
||||
box-shadow: 0 0 0 3px rgba(26,110,58,0.12);
|
||||
}
|
||||
.dataTables_wrapper .dataTables_length select {
|
||||
border-radius: 9px;
|
||||
border: 1.5px solid #e0ede0;
|
||||
padding: 5px 10px;
|
||||
font-size: 13px;
|
||||
margin: 0 6px;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_info {
|
||||
font-size: 12.5px;
|
||||
color: #8a9e8a;
|
||||
font-weight: 500;
|
||||
padding: 0;
|
||||
line-height: 36px;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate {
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
gap: 3px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button {
|
||||
box-sizing: border-box !important;
|
||||
width: 34px !important;
|
||||
height: 34px !important;
|
||||
min-width: 34px !important;
|
||||
border-radius: 50% !important;
|
||||
padding: 0 !important;
|
||||
margin: 0 2px !important;
|
||||
font-size: 13px !important;
|
||||
font-weight: 600 !important;
|
||||
border: 1.5px solid #e0ede0 !important;
|
||||
color: #5a6e5a !important;
|
||||
background: #ffffff !important;
|
||||
display: inline-flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
line-height: 1 !important;
|
||||
cursor: pointer !important;
|
||||
text-decoration: none !important;
|
||||
transition: all 0.15s ease !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button:hover:not(.disabled):not(.current) {
|
||||
background: #eaf7f0 !important;
|
||||
border-color: #2e9e58 !important;
|
||||
color: #1a6e3a !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button.current,
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button.current:hover {
|
||||
background: #ffffff !important;
|
||||
border: 2px solid #1a6e3a !important;
|
||||
color: #1a6e3a !important;
|
||||
box-shadow: 0 0 0 3px rgba(26,110,58,0.12) !important;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button.disabled,
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button.disabled:hover {
|
||||
color: #c8d8c8 !important;
|
||||
border-color: #edf5ed !important;
|
||||
background: #fafafa !important;
|
||||
cursor: default !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container-fluid">
|
||||
|
||||
{{-- PAGE HEADER --}}
|
||||
<div class="page-header">
|
||||
<div class="page-header-icon">
|
||||
<i class="fas fa-headset"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h1>Layanan Pengaduan</h1>
|
||||
<p>Manajemen pengaduan dan tanggapan penghuni</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if(session('success'))
|
||||
<div class="alert-success-custom">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- TABEL PENGADUAN --}}
|
||||
<div class="premium-card">
|
||||
<div class="premium-card-header">
|
||||
<div class="header-left">
|
||||
<div class="header-icon green"><i class="fas fa-clipboard-list"></i></div>
|
||||
<h6>Daftar Pengaduan</h6>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="premium-card-body" style="padding: 0;">
|
||||
<div class="table-responsive-wrapper">
|
||||
<table class="premium-table" id="dataTable" style="width:100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Nama</th>
|
||||
<th>Tanggal</th>
|
||||
<th>Kategori</th>
|
||||
<th>Deskripsi</th>
|
||||
<th>Foto</th>
|
||||
<th>Status</th>
|
||||
<th>Tanggapan</th>
|
||||
<th>Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($layanan as $item)
|
||||
<tr>
|
||||
<td>{{ $loop->iteration }}</td>
|
||||
|
||||
<td><strong>{{ $item->penghuni->nama ?? '-' }}</strong></td>
|
||||
|
||||
<td style="white-space:nowrap;">
|
||||
{{ \Carbon\Carbon::parse($item->tanggal_pengaduan)->translatedFormat('d M Y') }}
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<span class="badge-pill-custom badge-blue">
|
||||
<i class="fas fa-tag" style="font-size:9px"></i>
|
||||
{{ ucfirst($item->kategori_masalah) }}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<span class="desc-text" title="{{ $item->deskripsi }}">
|
||||
{{ \Illuminate\Support\Str::limit($item->deskripsi, 45) }}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
@if($item->foto)
|
||||
<img src="{{ asset('storage/' . $item->foto) }}" class="bukti-img">
|
||||
@else
|
||||
<span style="color:#ccc; font-size:12px;">—</span>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td>
|
||||
@if($item->status == 'diajukan')
|
||||
<span class="badge-pill-custom badge-yellow"><i class="fas fa-paper-plane" style="font-size:9px"></i> Diajukan</span>
|
||||
@elseif($item->status == 'menunggu')
|
||||
<span class="badge-pill-custom badge-blue"><i class="fas fa-hourglass-half" style="font-size:9px"></i> Menunggu</span>
|
||||
@elseif($item->status == 'selesai')
|
||||
<span class="badge-pill-custom badge-green"><i class="fas fa-check-circle" style="font-size:9px"></i> Selesai</span>
|
||||
@else
|
||||
<span class="badge-pill-custom badge-gray"><i class="fas fa-question-circle" style="font-size:9px"></i> Unknown</span>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td style="max-width: 180px;">
|
||||
@if($item->tanggapan_admin)
|
||||
<span class="desc-text" title="{{ $item->tanggapan_admin }}">
|
||||
{{ \Illuminate\Support\Str::limit($item->tanggapan_admin, 40) }}
|
||||
</span>
|
||||
@else
|
||||
<span style="color:#ccc; font-size:12px; font-style:italic;">Belum ada tanggapan</span>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td style="white-space:nowrap; min-width:160px;">
|
||||
{{-- RT: Tanggapi --}}
|
||||
@if(auth()->user()->role == 'rt' && $item->status == 'diajukan')
|
||||
<form action="{{ route('layanan.tanggapi.rt', $item->id) }}" method="POST">
|
||||
@csrf
|
||||
<div class="tanggapan-form">
|
||||
<textarea name="tanggapan_admin" rows="2" placeholder="Tulis tanggapan..." required></textarea>
|
||||
<button type="submit" class="btn-action success">
|
||||
<i class="fas fa-reply" style="font-size:10px"></i> Tanggapi
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@endif
|
||||
|
||||
{{-- ADMIN: Approve --}}
|
||||
@if(auth()->user()->role == 'admin' && $item->status == 'menunggu')
|
||||
<form action="{{ route('layanan.approve.admin', $item->id) }}" method="POST" style="display:inline;">
|
||||
@csrf
|
||||
<button class="btn-action success">
|
||||
<i class="fas fa-check-double" style="font-size:10px"></i> Approve
|
||||
</button>
|
||||
</form>
|
||||
@endif
|
||||
|
||||
{{-- HAPUS --}}
|
||||
<form action="{{ route('layanan.delete', $item->id) }}" method="POST" style="display:inline;">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button class="btn-action danger" onclick="return confirm('Yakin hapus pengaduan ini?')">
|
||||
<i class="fas fa-trash" style="font-size:10px"></i> Hapus
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="9" style="text-align:center; padding: 32px; color: #aaa;">
|
||||
<i class="fas fa-inbox" style="font-size:28px; display:block; margin-bottom:8px; opacity:0.4;"></i>
|
||||
Belum ada data pengaduan
|
||||
</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div> {{-- tutup table-responsive-wrapper --}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
if ($.fn.DataTable) {
|
||||
$('#dataTable').DataTable({
|
||||
pageLength: 10,
|
||||
lengthMenu: [5, 10, 25, 50],
|
||||
dom: '<"d-flex justify-content-between align-items-center px-3 pt-3"lf>t<"d-flex justify-content-between align-items-center px-3 pb-3"ip>',
|
||||
language: {
|
||||
search: "Cari:",
|
||||
lengthMenu: "Tampilkan _MENU_ data",
|
||||
info: "Menampilkan _START_–_END_ dari _TOTAL_ data",
|
||||
infoEmpty: "Tidak ada data",
|
||||
paginate: {
|
||||
first: "«",
|
||||
last: "»",
|
||||
next: "›",
|
||||
previous: "‹"
|
||||
},
|
||||
emptyTable: "Belum ada data pengaduan"
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
|
|
@ -0,0 +1,492 @@
|
|||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
*, *::before, *::after { box-sizing: border-box; }
|
||||
body { font-family: 'Plus Jakarta Sans', sans-serif; }
|
||||
|
||||
/* ── PAGE HEADER ── */
|
||||
.page-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
.page-header-icon {
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
background: linear-gradient(135deg, #064e3b, #0d6e4f);
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
font-size: 20px;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0 4px 14px rgba(6,78,59,0.3);
|
||||
}
|
||||
.page-header h1 {
|
||||
font-size: 22px;
|
||||
font-weight: 800;
|
||||
color: #1a2e1a;
|
||||
margin: 0;
|
||||
line-height: 1.2;
|
||||
}
|
||||
.page-header p {
|
||||
font-size: 13px;
|
||||
color: #8a9e8a;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ── ALERT ── */
|
||||
.alert-success-custom {
|
||||
background: #f0faf4;
|
||||
border: 1px solid #a8e6be;
|
||||
border-left: 4px solid #1a6e3a;
|
||||
border-radius: 12px;
|
||||
padding: 12px 16px;
|
||||
color: #1a4e2a;
|
||||
font-size: 13.5px;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
/* ── CARD ── */
|
||||
.premium-card {
|
||||
background: #ffffff;
|
||||
border-radius: 16px;
|
||||
border: 1px solid #e8f0e8;
|
||||
box-shadow: 0 2px 12px rgba(0,0,0,0.05);
|
||||
margin-bottom: 24px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.premium-card-header {
|
||||
padding: 16px 22px;
|
||||
background: #ffffff;
|
||||
border-bottom: 1px solid #f0f5f0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.premium-card-header .header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
.header-icon {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
border-radius: 9px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 15px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.header-icon.green { background: #d1fae5; color: #064e3b; }
|
||||
.premium-card-header h6 {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: #1a2e1a;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ── TABLE ── */
|
||||
.premium-table {
|
||||
width: 100%;
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
font-size: 13px;
|
||||
}
|
||||
.premium-table thead tr th {
|
||||
background: #f6fbf7;
|
||||
color: #3a5a3a;
|
||||
font-weight: 700;
|
||||
font-size: 11.5px;
|
||||
letter-spacing: 0.5px;
|
||||
text-transform: uppercase;
|
||||
padding: 11px 14px;
|
||||
border-bottom: 2px solid #e0ede0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.premium-table thead tr th:first-child { border-radius: 10px 0 0 0; }
|
||||
.premium-table thead tr th:last-child { border-radius: 0 10px 0 0; }
|
||||
.premium-table tbody tr td {
|
||||
padding: 11px 14px;
|
||||
border-bottom: 1px solid #f2f7f2;
|
||||
color: #2a3a2a;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.premium-table tbody tr:hover td { background: #f8fdf8; }
|
||||
.premium-table tbody tr:last-child td { border-bottom: none; }
|
||||
|
||||
/* ── BADGES ── */
|
||||
.badge-pill-custom {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 99px;
|
||||
font-size: 11.5px;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.badge-green { background: #d1fae5; color: #064e3b; }
|
||||
.badge-red { background: #fdf0f0; color: #c53030; }
|
||||
.badge-yellow { background: #fdfbea; color: #7a6010; }
|
||||
.badge-blue { background: #eaf0fb; color: #1a4e8e; }
|
||||
.badge-gray { background: #f3f4f6; color: #4b5563; }
|
||||
|
||||
/* ── ACTION BUTTONS ── */
|
||||
.btn-action {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
padding: 5px 11px;
|
||||
border-radius: 8px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
text-decoration: none;
|
||||
transition: opacity 0.15s, transform 0.1s;
|
||||
}
|
||||
.btn-action:hover { opacity: 0.85; transform: translateY(-1px); text-decoration: none; }
|
||||
.btn-action:active { transform: translateY(0); }
|
||||
.btn-action.info { background: #eaf0fb; color: #1a4e8e; }
|
||||
.btn-action.warn { background: #fdf8ea; color: #8a6000; }
|
||||
.btn-action.danger { background: #fdf0f0; color: #c53030; }
|
||||
.btn-action.success { background: #d1fae5; color: #064e3b; }
|
||||
|
||||
/* ── TANGGAPAN FORM ── */
|
||||
.tanggapan-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
min-width: 180px;
|
||||
}
|
||||
.tanggapan-form textarea {
|
||||
border-radius: 9px !important;
|
||||
border: 1.5px solid #e0ede0 !important;
|
||||
font-size: 12px !important;
|
||||
padding: 7px 10px !important;
|
||||
resize: none;
|
||||
font-family: 'Plus Jakarta Sans', sans-serif;
|
||||
outline: none;
|
||||
transition: border-color 0.15s;
|
||||
}
|
||||
.tanggapan-form textarea:focus {
|
||||
border-color: #1a6e3a !important;
|
||||
box-shadow: 0 0 0 3px rgba(26,110,58,0.1);
|
||||
}
|
||||
|
||||
/* ── FOTO ── */
|
||||
.bukti-img {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: 8px;
|
||||
object-fit: cover;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.12);
|
||||
cursor: pointer;
|
||||
transition: transform 0.15s;
|
||||
}
|
||||
.bukti-img:hover { transform: scale(1.1); }
|
||||
|
||||
/* ── DESKRIPSI TRUNCATE ── */
|
||||
.desc-text {
|
||||
max-width: 200px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* ── MOBILE RESPONSIVE ── */
|
||||
.table-responsive-wrapper {
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.premium-table {
|
||||
min-width: 750px;
|
||||
}
|
||||
.page-header h1 { font-size: 18px; }
|
||||
.desc-text { max-width: 140px; }
|
||||
}
|
||||
|
||||
/* ── DATATABLES ── */
|
||||
.dataTables_wrapper { padding: 0; }
|
||||
.dataTables_wrapper .dataTables_length label,
|
||||
.dataTables_wrapper .dataTables_filter label {
|
||||
font-size: 13px;
|
||||
color: #5a6e5a;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin: 0;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_filter input {
|
||||
border-radius: 9px;
|
||||
border: 1.5px solid #e0ede0;
|
||||
padding: 6px 12px;
|
||||
font-size: 13px;
|
||||
outline: none;
|
||||
margin-left: 6px;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_filter input:focus {
|
||||
border-color: #1a6e3a;
|
||||
box-shadow: 0 0 0 3px rgba(26,110,58,0.12);
|
||||
}
|
||||
.dataTables_wrapper .dataTables_length select {
|
||||
border-radius: 9px;
|
||||
border: 1.5px solid #e0ede0;
|
||||
padding: 5px 10px;
|
||||
font-size: 13px;
|
||||
margin: 0 6px;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_info {
|
||||
font-size: 12.5px;
|
||||
color: #8a9e8a;
|
||||
font-weight: 500;
|
||||
padding: 0;
|
||||
line-height: 36px;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate {
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
gap: 3px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button {
|
||||
box-sizing: border-box !important;
|
||||
width: 34px !important;
|
||||
height: 34px !important;
|
||||
min-width: 34px !important;
|
||||
border-radius: 50% !important;
|
||||
padding: 0 !important;
|
||||
margin: 0 2px !important;
|
||||
font-size: 13px !important;
|
||||
font-weight: 600 !important;
|
||||
border: 1.5px solid #e0ede0 !important;
|
||||
color: #5a6e5a !important;
|
||||
background: #ffffff !important;
|
||||
display: inline-flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
line-height: 1 !important;
|
||||
cursor: pointer !important;
|
||||
text-decoration: none !important;
|
||||
transition: all 0.15s ease !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button:hover:not(.disabled):not(.current) {
|
||||
background: #eaf7f0 !important;
|
||||
border-color: #2e9e58 !important;
|
||||
color: #1a6e3a !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button.current,
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button.current:hover {
|
||||
background: #ffffff !important;
|
||||
border: 2px solid #1a6e3a !important;
|
||||
color: #1a6e3a !important;
|
||||
box-shadow: 0 0 0 3px rgba(26,110,58,0.12) !important;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button.disabled,
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button.disabled:hover {
|
||||
color: #c8d8c8 !important;
|
||||
border-color: #edf5ed !important;
|
||||
background: #fafafa !important;
|
||||
cursor: default !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container-fluid">
|
||||
|
||||
{{-- PAGE HEADER --}}
|
||||
<div class="page-header">
|
||||
<div class="page-header-icon">
|
||||
<i class="fas fa-headset"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h1>Layanan Pengaduan</h1>
|
||||
<p>Manajemen pengaduan dan tanggapan penghuni</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if(session('success'))
|
||||
<div class="alert-success-custom">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- TABEL PENGADUAN --}}
|
||||
<div class="premium-card">
|
||||
<div class="premium-card-header">
|
||||
<div class="header-left">
|
||||
<div class="header-icon green"><i class="fas fa-clipboard-list"></i></div>
|
||||
<h6>Daftar Pengaduan</h6>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="premium-card-body" style="padding: 0;">
|
||||
<div class="table-responsive-wrapper">
|
||||
<table class="premium-table" id="dataTable" style="width:100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Nama</th>
|
||||
<th>Tanggal</th>
|
||||
<th>Kategori</th>
|
||||
<th>Deskripsi</th>
|
||||
<th>Foto</th>
|
||||
<th>Status</th>
|
||||
<th>Tanggapan</th>
|
||||
<th>Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($layanan as $item)
|
||||
<tr>
|
||||
<td>{{ $loop->iteration }}</td>
|
||||
|
||||
<td><strong>{{ $item->penghuni->nama ?? '-' }}</strong></td>
|
||||
|
||||
<td style="white-space:nowrap;">
|
||||
{{ \Carbon\Carbon::parse($item->tanggal_pengaduan)->translatedFormat('d M Y') }}
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<span class="badge-pill-custom badge-blue">
|
||||
<i class="fas fa-tag" style="font-size:9px"></i>
|
||||
{{ ucfirst($item->kategori_masalah) }}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<span class="desc-text" title="{{ $item->deskripsi }}">
|
||||
{{ \Illuminate\Support\Str::limit($item->deskripsi, 45) }}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
@if($item->foto)
|
||||
<img src="{{ asset('storage/' . $item->foto) }}" class="bukti-img">
|
||||
@else
|
||||
<span style="color:#ccc; font-size:12px;">—</span>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td>
|
||||
@if($item->status == 'diajukan')
|
||||
<span class="badge-pill-custom badge-yellow"><i class="fas fa-paper-plane" style="font-size:9px"></i> Diajukan</span>
|
||||
@elseif($item->status == 'menunggu')
|
||||
<span class="badge-pill-custom badge-blue"><i class="fas fa-hourglass-half" style="font-size:9px"></i> Menunggu</span>
|
||||
@elseif($item->status == 'selesai')
|
||||
<span class="badge-pill-custom badge-green"><i class="fas fa-check-circle" style="font-size:9px"></i> Selesai</span>
|
||||
@else
|
||||
<span class="badge-pill-custom badge-gray"><i class="fas fa-question-circle" style="font-size:9px"></i> Unknown</span>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td style="max-width: 180px;">
|
||||
@if($item->tanggapan_admin)
|
||||
<span class="desc-text" title="{{ $item->tanggapan_admin }}">
|
||||
{{ \Illuminate\Support\Str::limit($item->tanggapan_admin, 40) }}
|
||||
</span>
|
||||
@else
|
||||
<span style="color:#ccc; font-size:12px; font-style:italic;">Belum ada tanggapan</span>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td style="white-space:nowrap; min-width:160px;">
|
||||
{{-- RT: Tanggapi --}}
|
||||
@if(auth()->user()->role == 'rt' && $item->status == 'diajukan')
|
||||
<form action="{{ route('layanan.tanggapi.rt', $item->id) }}" method="POST">
|
||||
@csrf
|
||||
<div class="tanggapan-form">
|
||||
<textarea name="tanggapan_admin" rows="2" placeholder="Tulis tanggapan..." required></textarea>
|
||||
<button type="submit" class="btn-action success">
|
||||
<i class="fas fa-reply" style="font-size:10px"></i> Tanggapi
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@endif
|
||||
|
||||
{{-- ADMIN: Approve --}}
|
||||
@if(auth()->user()->role == 'admin' && $item->status == 'menunggu')
|
||||
<form action="{{ route('layanan.approve.admin', $item->id) }}" method="POST" style="display:inline;">
|
||||
@csrf
|
||||
<button class="btn-action success">
|
||||
<i class="fas fa-check-double" style="font-size:10px"></i> Approve
|
||||
</button>
|
||||
</form>
|
||||
@endif
|
||||
|
||||
{{-- HAPUS --}}
|
||||
<form action="{{ route('layanan.delete', $item->id) }}" method="POST" style="display:inline;">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button class="btn-action danger" onclick="return confirm('Yakin hapus pengaduan ini?')">
|
||||
<i class="fas fa-trash" style="font-size:10px"></i> Hapus
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="9" style="text-align:center; padding: 32px; color: #aaa;">
|
||||
<i class="fas fa-inbox" style="font-size:28px; display:block; margin-bottom:8px; opacity:0.4;"></i>
|
||||
Belum ada data pengaduan
|
||||
</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div> {{-- tutup table-responsive-wrapper --}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
if ($.fn.DataTable) {
|
||||
$('#dataTable').DataTable({
|
||||
pageLength: 10,
|
||||
lengthMenu: [5, 10, 25, 50],
|
||||
dom: '<"d-flex justify-content-between align-items-center px-3 pt-3"lf>t<"d-flex justify-content-between align-items-center px-3 pb-3"ip>',
|
||||
language: {
|
||||
search: "Cari:",
|
||||
lengthMenu: "Tampilkan _MENU_ data",
|
||||
info: "Menampilkan _START_–_END_ dari _TOTAL_ data",
|
||||
infoEmpty: "Tidak ada data",
|
||||
paginate: {
|
||||
first: "«",
|
||||
last: "»",
|
||||
next: "›",
|
||||
previous: "‹"
|
||||
},
|
||||
emptyTable: "Belum ada data pengaduan"
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
|
|
@ -0,0 +1,492 @@
|
|||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
*, *::before, *::after { box-sizing: border-box; }
|
||||
body { font-family: 'Plus Jakarta Sans', sans-serif; }
|
||||
|
||||
/* ── PAGE HEADER ── */
|
||||
.page-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
.page-header-icon {
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
background: linear-gradient(135deg, #064e3b, #0d6e4f);
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
font-size: 20px;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0 4px 14px rgba(6,78,59,0.3);
|
||||
}
|
||||
.page-header h1 {
|
||||
font-size: 22px;
|
||||
font-weight: 800;
|
||||
color: #1a2e1a;
|
||||
margin: 0;
|
||||
line-height: 1.2;
|
||||
}
|
||||
.page-header p {
|
||||
font-size: 13px;
|
||||
color: #8a9e8a;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ── ALERT ── */
|
||||
.alert-success-custom {
|
||||
background: #f0faf4;
|
||||
border: 1px solid #a8e6be;
|
||||
border-left: 4px solid #1a6e3a;
|
||||
border-radius: 12px;
|
||||
padding: 12px 16px;
|
||||
color: #1a4e2a;
|
||||
font-size: 13.5px;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
/* ── CARD ── */
|
||||
.premium-card {
|
||||
background: #ffffff;
|
||||
border-radius: 16px;
|
||||
border: 1px solid #e8f0e8;
|
||||
box-shadow: 0 2px 12px rgba(0,0,0,0.05);
|
||||
margin-bottom: 24px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.premium-card-header {
|
||||
padding: 16px 22px;
|
||||
background: #ffffff;
|
||||
border-bottom: 1px solid #f0f5f0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.premium-card-header .header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
.header-icon {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
border-radius: 9px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 15px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.header-icon.green { background: #d1fae5; color: #064e3b; }
|
||||
.premium-card-header h6 {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: #1a2e1a;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ── TABLE ── */
|
||||
.premium-table {
|
||||
width: 100%;
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
font-size: 13px;
|
||||
}
|
||||
.premium-table thead tr th {
|
||||
background: #f6fbf7;
|
||||
color: #3a5a3a;
|
||||
font-weight: 700;
|
||||
font-size: 11.5px;
|
||||
letter-spacing: 0.5px;
|
||||
text-transform: uppercase;
|
||||
padding: 11px 14px;
|
||||
border-bottom: 2px solid #e0ede0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.premium-table thead tr th:first-child { border-radius: 10px 0 0 0; }
|
||||
.premium-table thead tr th:last-child { border-radius: 0 10px 0 0; }
|
||||
.premium-table tbody tr td {
|
||||
padding: 11px 14px;
|
||||
border-bottom: 1px solid #f2f7f2;
|
||||
color: #2a3a2a;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.premium-table tbody tr:hover td { background: #f8fdf8; }
|
||||
.premium-table tbody tr:last-child td { border-bottom: none; }
|
||||
|
||||
/* ── BADGES ── */
|
||||
.badge-pill-custom {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
padding: 4px 10px;
|
||||
border-radius: 99px;
|
||||
font-size: 11.5px;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.badge-green { background: #d1fae5; color: #064e3b; }
|
||||
.badge-red { background: #fdf0f0; color: #c53030; }
|
||||
.badge-yellow { background: #fdfbea; color: #7a6010; }
|
||||
.badge-blue { background: #eaf0fb; color: #1a4e8e; }
|
||||
.badge-gray { background: #f3f4f6; color: #4b5563; }
|
||||
|
||||
/* ── ACTION BUTTONS ── */
|
||||
.btn-action {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
padding: 5px 11px;
|
||||
border-radius: 8px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
text-decoration: none;
|
||||
transition: opacity 0.15s, transform 0.1s;
|
||||
}
|
||||
.btn-action:hover { opacity: 0.85; transform: translateY(-1px); text-decoration: none; }
|
||||
.btn-action:active { transform: translateY(0); }
|
||||
.btn-action.info { background: #eaf0fb; color: #1a4e8e; }
|
||||
.btn-action.warn { background: #fdf8ea; color: #8a6000; }
|
||||
.btn-action.danger { background: #fdf0f0; color: #c53030; }
|
||||
.btn-action.success { background: #d1fae5; color: #064e3b; }
|
||||
|
||||
/* ── TANGGAPAN FORM ── */
|
||||
.tanggapan-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
min-width: 180px;
|
||||
}
|
||||
.tanggapan-form textarea {
|
||||
border-radius: 9px !important;
|
||||
border: 1.5px solid #e0ede0 !important;
|
||||
font-size: 12px !important;
|
||||
padding: 7px 10px !important;
|
||||
resize: none;
|
||||
font-family: 'Plus Jakarta Sans', sans-serif;
|
||||
outline: none;
|
||||
transition: border-color 0.15s;
|
||||
}
|
||||
.tanggapan-form textarea:focus {
|
||||
border-color: #1a6e3a !important;
|
||||
box-shadow: 0 0 0 3px rgba(26,110,58,0.1);
|
||||
}
|
||||
|
||||
/* ── FOTO ── */
|
||||
.bukti-img {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: 8px;
|
||||
object-fit: cover;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.12);
|
||||
cursor: pointer;
|
||||
transition: transform 0.15s;
|
||||
}
|
||||
.bukti-img:hover { transform: scale(1.1); }
|
||||
|
||||
/* ── DESKRIPSI TRUNCATE ── */
|
||||
.desc-text {
|
||||
max-width: 200px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* ── MOBILE RESPONSIVE ── */
|
||||
.table-responsive-wrapper {
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.premium-table {
|
||||
min-width: 750px;
|
||||
}
|
||||
.page-header h1 { font-size: 18px; }
|
||||
.desc-text { max-width: 140px; }
|
||||
}
|
||||
|
||||
/* ── DATATABLES ── */
|
||||
.dataTables_wrapper { padding: 0; }
|
||||
.dataTables_wrapper .dataTables_length label,
|
||||
.dataTables_wrapper .dataTables_filter label {
|
||||
font-size: 13px;
|
||||
color: #5a6e5a;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin: 0;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_filter input {
|
||||
border-radius: 9px;
|
||||
border: 1.5px solid #e0ede0;
|
||||
padding: 6px 12px;
|
||||
font-size: 13px;
|
||||
outline: none;
|
||||
margin-left: 6px;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_filter input:focus {
|
||||
border-color: #1a6e3a;
|
||||
box-shadow: 0 0 0 3px rgba(26,110,58,0.12);
|
||||
}
|
||||
.dataTables_wrapper .dataTables_length select {
|
||||
border-radius: 9px;
|
||||
border: 1.5px solid #e0ede0;
|
||||
padding: 5px 10px;
|
||||
font-size: 13px;
|
||||
margin: 0 6px;
|
||||
}
|
||||
.dataTables_wrapper .dataTables_info {
|
||||
font-size: 12.5px;
|
||||
color: #8a9e8a;
|
||||
font-weight: 500;
|
||||
padding: 0;
|
||||
line-height: 36px;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate {
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
gap: 3px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button {
|
||||
box-sizing: border-box !important;
|
||||
width: 34px !important;
|
||||
height: 34px !important;
|
||||
min-width: 34px !important;
|
||||
border-radius: 50% !important;
|
||||
padding: 0 !important;
|
||||
margin: 0 2px !important;
|
||||
font-size: 13px !important;
|
||||
font-weight: 600 !important;
|
||||
border: 1.5px solid #e0ede0 !important;
|
||||
color: #5a6e5a !important;
|
||||
background: #ffffff !important;
|
||||
display: inline-flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
line-height: 1 !important;
|
||||
cursor: pointer !important;
|
||||
text-decoration: none !important;
|
||||
transition: all 0.15s ease !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button:hover:not(.disabled):not(.current) {
|
||||
background: #eaf7f0 !important;
|
||||
border-color: #2e9e58 !important;
|
||||
color: #1a6e3a !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button.current,
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button.current:hover {
|
||||
background: #ffffff !important;
|
||||
border: 2px solid #1a6e3a !important;
|
||||
color: #1a6e3a !important;
|
||||
box-shadow: 0 0 0 3px rgba(26,110,58,0.12) !important;
|
||||
}
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button.disabled,
|
||||
div.dataTables_wrapper div.dataTables_paginate .paginate_button.disabled:hover {
|
||||
color: #c8d8c8 !important;
|
||||
border-color: #edf5ed !important;
|
||||
background: #fafafa !important;
|
||||
cursor: default !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container-fluid">
|
||||
|
||||
{{-- PAGE HEADER --}}
|
||||
<div class="page-header">
|
||||
<div class="page-header-icon">
|
||||
<i class="fas fa-headset"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h1>Layanan Pengaduan</h1>
|
||||
<p>Manajemen pengaduan dan tanggapan penghuni</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if(session('success'))
|
||||
<div class="alert-success-custom">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- TABEL PENGADUAN --}}
|
||||
<div class="premium-card">
|
||||
<div class="premium-card-header">
|
||||
<div class="header-left">
|
||||
<div class="header-icon green"><i class="fas fa-clipboard-list"></i></div>
|
||||
<h6>Daftar Pengaduan</h6>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="premium-card-body" style="padding: 0;">
|
||||
<div class="table-responsive-wrapper">
|
||||
<table class="premium-table" id="dataTable" style="width:100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Nama</th>
|
||||
<th>Tanggal</th>
|
||||
<th>Kategori</th>
|
||||
<th>Deskripsi</th>
|
||||
<th>Foto</th>
|
||||
<th>Status</th>
|
||||
<th>Tanggapan</th>
|
||||
<th>Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($layanan as $item)
|
||||
<tr>
|
||||
<td>{{ $loop->iteration }}</td>
|
||||
|
||||
<td><strong>{{ $item->penghuni->nama ?? '-' }}</strong></td>
|
||||
|
||||
<td style="white-space:nowrap;">
|
||||
{{ \Carbon\Carbon::parse($item->tanggal_pengaduan)->translatedFormat('d M Y') }}
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<span class="badge-pill-custom badge-blue">
|
||||
<i class="fas fa-tag" style="font-size:9px"></i>
|
||||
{{ ucfirst($item->kategori_masalah) }}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<span class="desc-text" title="{{ $item->deskripsi }}">
|
||||
{{ \Illuminate\Support\Str::limit($item->deskripsi, 45) }}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
@if($item->foto)
|
||||
<img src="{{ asset('storage/' . $item->foto) }}" class="bukti-img">
|
||||
@else
|
||||
<span style="color:#ccc; font-size:12px;">—</span>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td>
|
||||
@if($item->status == 'diajukan')
|
||||
<span class="badge-pill-custom badge-yellow"><i class="fas fa-paper-plane" style="font-size:9px"></i> Diajukan</span>
|
||||
@elseif($item->status == 'menunggu')
|
||||
<span class="badge-pill-custom badge-blue"><i class="fas fa-hourglass-half" style="font-size:9px"></i> Menunggu</span>
|
||||
@elseif($item->status == 'selesai')
|
||||
<span class="badge-pill-custom badge-green"><i class="fas fa-check-circle" style="font-size:9px"></i> Selesai</span>
|
||||
@else
|
||||
<span class="badge-pill-custom badge-gray"><i class="fas fa-question-circle" style="font-size:9px"></i> Unknown</span>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td style="max-width: 180px;">
|
||||
@if($item->tanggapan_admin)
|
||||
<span class="desc-text" title="{{ $item->tanggapan_admin }}">
|
||||
{{ \Illuminate\Support\Str::limit($item->tanggapan_admin, 40) }}
|
||||
</span>
|
||||
@else
|
||||
<span style="color:#ccc; font-size:12px; font-style:italic;">Belum ada tanggapan</span>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
<td style="white-space:nowrap; min-width:160px;">
|
||||
{{-- RT: Tanggapi --}}
|
||||
@if(auth()->user()->role == 'rt' && $item->status == 'diajukan')
|
||||
<form action="{{ route('layanan.tanggapi.rt', $item->id) }}" method="POST">
|
||||
@csrf
|
||||
<div class="tanggapan-form">
|
||||
<textarea name="tanggapan_admin" rows="2" placeholder="Tulis tanggapan..." required></textarea>
|
||||
<button type="submit" class="btn-action success">
|
||||
<i class="fas fa-reply" style="font-size:10px"></i> Tanggapi
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@endif
|
||||
|
||||
{{-- ADMIN: Approve --}}
|
||||
@if(auth()->user()->role == 'admin' && $item->status == 'menunggu')
|
||||
<form action="{{ route('layanan.approve.admin', $item->id) }}" method="POST" style="display:inline;">
|
||||
@csrf
|
||||
<button class="btn-action success">
|
||||
<i class="fas fa-check-double" style="font-size:10px"></i> Approve
|
||||
</button>
|
||||
</form>
|
||||
@endif
|
||||
|
||||
{{-- HAPUS --}}
|
||||
<form action="{{ route('layanan.delete', $item->id) }}" method="POST" style="display:inline;">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button class="btn-action danger" onclick="return confirm('Yakin hapus pengaduan ini?')">
|
||||
<i class="fas fa-trash" style="font-size:10px"></i> Hapus
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="9" style="text-align:center; padding: 32px; color: #aaa;">
|
||||
<i class="fas fa-inbox" style="font-size:28px; display:block; margin-bottom:8px; opacity:0.4;"></i>
|
||||
Belum ada data pengaduan
|
||||
</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div> {{-- tutup table-responsive-wrapper --}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
if ($.fn.DataTable) {
|
||||
$('#dataTable').DataTable({
|
||||
pageLength: 10,
|
||||
lengthMenu: [5, 10, 25, 50],
|
||||
dom: '<"d-flex justify-content-between align-items-center px-3 pt-3"lf>t<"d-flex justify-content-between align-items-center px-3 pb-3"ip>',
|
||||
language: {
|
||||
search: "Cari:",
|
||||
lengthMenu: "Tampilkan _MENU_ data",
|
||||
info: "Menampilkan _START_–_END_ dari _TOTAL_ data",
|
||||
infoEmpty: "Tidak ada data",
|
||||
paginate: {
|
||||
first: "«",
|
||||
last: "»",
|
||||
next: "›",
|
||||
previous: "‹"
|
||||
},
|
||||
emptyTable: "Belum ada data pengaduan"
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
|
|
@ -0,0 +1,508 @@
|
|||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
|
||||
{{-- ============================================================
|
||||
FILE: resources/views/admin/user/index.blade.php
|
||||
============================================================ --}}
|
||||
|
||||
<style>
|
||||
body { background: #f0f4f8 !important; }
|
||||
|
||||
.page-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.page-header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.page-icon {
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
background: linear-gradient(135deg, #064e3b, #0d6e4f);
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 18px;
|
||||
flex-shrink: 0;
|
||||
color: #fff;
|
||||
box-shadow: 0 4px 14px rgba(6,78,59,0.3);
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: 22px;
|
||||
font-weight: 800;
|
||||
color: #111827;
|
||||
margin: 0;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.page-subtitle {
|
||||
font-size: 13px;
|
||||
color: #6b7280;
|
||||
margin: 2px 0 0;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 16px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
background: #ffffff;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 16px;
|
||||
padding: 20px 22px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.04);
|
||||
animation: fadeUp 0.35s ease;
|
||||
transition: all 0.15s ease;
|
||||
}
|
||||
|
||||
.stat-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 20px rgba(0,0,0,0.08);
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 28px;
|
||||
font-weight: 800;
|
||||
line-height: 1.1;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 12.5px;
|
||||
color: #6b7280;
|
||||
font-weight: 500;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.stat-card:nth-child(1) .stat-value { color: #111827; }
|
||||
.stat-card:nth-child(2) .stat-value { color: #064e3b; }
|
||||
.stat-card:nth-child(3) .stat-value { color: #f59e0b; }
|
||||
|
||||
/* ── FILTER TABS ── */
|
||||
.filter-tabs {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-bottom: 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.filter-tab {
|
||||
padding: 7px 18px;
|
||||
border-radius: 999px;
|
||||
font-size: 12.5px;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
border: 1.5px solid transparent;
|
||||
transition: all 0.15s ease;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
background: #ffffff;
|
||||
color: #6b7280;
|
||||
border-color: #e5e7eb;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.filter-tab .tab-count {
|
||||
background: #f3f4f6;
|
||||
color: #6b7280;
|
||||
border-radius: 999px;
|
||||
padding: 1px 7px;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
transition: all 0.15s ease;
|
||||
}
|
||||
|
||||
.filter-tab:hover {
|
||||
border-color: #d1d5db;
|
||||
background: #f9fafb;
|
||||
}
|
||||
|
||||
/* All tab */
|
||||
.filter-tab[data-filter="all"].active {
|
||||
background: #111827;
|
||||
color: #ffffff;
|
||||
border-color: #111827;
|
||||
}
|
||||
.filter-tab[data-filter="all"].active .tab-count {
|
||||
background: rgba(255,255,255,0.2);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* RT tab */
|
||||
.filter-tab[data-filter="rt"].active {
|
||||
background: #fffbeb;
|
||||
color: #d97706;
|
||||
border-color: #fcd34d;
|
||||
}
|
||||
.filter-tab[data-filter="rt"].active .tab-count {
|
||||
background: #fde68a;
|
||||
color: #d97706;
|
||||
}
|
||||
|
||||
/* User tab */
|
||||
.filter-tab[data-filter="user"].active {
|
||||
background: #f0fdf4;
|
||||
color: #064e3b;
|
||||
border-color: #6ee7b7;
|
||||
}
|
||||
.filter-tab[data-filter="user"].active .tab-count {
|
||||
background: #bbf7d0;
|
||||
color: #064e3b;
|
||||
}
|
||||
|
||||
.card {
|
||||
border: 1px solid #e5e7eb !important;
|
||||
border-radius: 16px !important;
|
||||
background: #ffffff;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.05) !important;
|
||||
overflow: hidden;
|
||||
animation: fadeUp 0.35s ease;
|
||||
}
|
||||
|
||||
@keyframes fadeUp {
|
||||
from { opacity: 0; transform: translateY(12px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
.table { margin-bottom: 0; }
|
||||
|
||||
.table thead th {
|
||||
background: #f9fafb !important;
|
||||
color: #6b7280 !important;
|
||||
font-size: 11px !important;
|
||||
font-weight: 700 !important;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
border-bottom: 1px solid #e5e7eb !important;
|
||||
border-top: none !important;
|
||||
padding: 11px 18px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.table tbody td {
|
||||
color: #111827;
|
||||
font-size: 13.5px;
|
||||
padding: 15px 18px;
|
||||
border-bottom: 1px solid #f3f4f6 !important;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.table tbody tr:last-child td { border-bottom: none !important; }
|
||||
.table tbody tr:hover td { background: #fafafa; }
|
||||
|
||||
.nama-cell { font-weight: 700; color: #111827; }
|
||||
.email-cell { color: #6b7280; font-size: 13px; }
|
||||
|
||||
.badge-role {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 4px 12px;
|
||||
border-radius: 999px;
|
||||
font-size: 11.5px;
|
||||
font-weight: 700;
|
||||
text-transform: lowercase;
|
||||
}
|
||||
|
||||
.badge-user { background: #f0fdf4; color: #064e3b; border: 1px solid #bbf7d0; }
|
||||
.badge-rt { background: #fffbeb; color: #d97706; border: 1px solid #fde68a; }
|
||||
|
||||
.btn {
|
||||
border-radius: 8px !important;
|
||||
font-size: 12px;
|
||||
padding: 6px 14px;
|
||||
font-weight: 600;
|
||||
transition: all 0.15s ease;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn-tambah {
|
||||
background: linear-gradient(135deg, #064e3b, #0d6e4f) !important;
|
||||
border: none !important;
|
||||
color: #ffffff !important;
|
||||
border-radius: 10px !important;
|
||||
padding: 9px 18px;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
text-decoration: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
transition: all 0.15s ease;
|
||||
box-shadow: 0 3px 10px rgba(6,78,59,0.3);
|
||||
}
|
||||
|
||||
.btn-tambah:hover { opacity: 0.9; color: #fff !important; transform: translateY(-1px); }
|
||||
|
||||
.btn-edit { background: #fff7ed !important; border: 1px solid #fed7aa !important; color: #ea580c !important; }
|
||||
.btn-edit:hover { background: #ffedd5 !important; }
|
||||
|
||||
.btn-hapus { background: #fef2f2 !important; border: 1px solid #fecaca !important; color: #dc2626 !important; }
|
||||
.btn-hapus:hover { background: #fee2e2 !important; }
|
||||
|
||||
.action-gap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.pagination-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 14px 18px;
|
||||
border-top: 1px solid #f3f4f6;
|
||||
}
|
||||
|
||||
.pagination-info { font-size: 12.5px; color: #6b7280; }
|
||||
|
||||
.pagination {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.pagination .page-item .page-link {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 8px !important;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #374151;
|
||||
background: #ffffff;
|
||||
border: 1px solid #e5e7eb !important;
|
||||
text-decoration: none;
|
||||
transition: all 0.15s ease;
|
||||
}
|
||||
|
||||
.pagination .page-item .page-link:hover { background: #f0fdf4; border-color: #064e3b !important; color: #064e3b; }
|
||||
.pagination .page-item.active .page-link { background: #064e3b !important; border-color: #064e3b !important; color: #ffffff !important; }
|
||||
.pagination .page-item.disabled .page-link { background: #f9fafb; color: #d1d5db; cursor: not-allowed; }
|
||||
|
||||
.alert-success-custom {
|
||||
background: #f0fdf4;
|
||||
border: 1px solid #bbf7d0;
|
||||
color: #15803d;
|
||||
border-radius: 10px;
|
||||
font-size: 13px;
|
||||
padding: 10px 16px;
|
||||
margin-bottom: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.user-row.hidden-by-filter { display: none !important; }
|
||||
</style>
|
||||
|
||||
<div class="container-fluid" style="padding: 28px 28px;">
|
||||
|
||||
<div class="page-header">
|
||||
<div class="page-header-left">
|
||||
<div class="page-icon">
|
||||
<i class="fas fa-users-cog"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h1 class="page-title">Kelola Data User</h1>
|
||||
<p class="page-subtitle">Manajemen akun dan hak akses pengguna</p>
|
||||
</div>
|
||||
</div>
|
||||
<a href="{{ route('admin.user.create') }}" class="btn-tambah">
|
||||
<i class="fas fa-plus" style="font-size:11px;"></i> Tambah User RT
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{{-- STATS: hanya Total (rt+user), User, RT — admin disembunyikan --}}
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card">
|
||||
<p class="stat-value">{{ $user->whereIn('role', ['rt','user'])->count() }}</p>
|
||||
<p class="stat-label">Total User</p>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<p class="stat-value">{{ $user->where('role','user')->count() }}</p>
|
||||
<p class="stat-label">User</p>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<p class="stat-value">{{ $user->where('role','rt')->count() }}</p>
|
||||
<p class="stat-label">RT</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if(session('success'))
|
||||
<div class="alert-success-custom">
|
||||
<i class="fas fa-check-circle"></i> {{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Filter Tabs: admin dihapus --}}
|
||||
<div class="filter-tabs">
|
||||
<button class="filter-tab active" data-filter="all">
|
||||
<i class="fas fa-users" style="font-size:11px;"></i> Semua
|
||||
<span class="tab-count" id="count-all">{{ $user->whereIn('role', ['rt','user'])->count() }}</span>
|
||||
</button>
|
||||
<button class="filter-tab" data-filter="rt">
|
||||
<i class="fas fa-home" style="font-size:11px;"></i> RT
|
||||
<span class="tab-count" id="count-rt">{{ $user->where('role','rt')->count() }}</span>
|
||||
</button>
|
||||
<button class="filter-tab" data-filter="user">
|
||||
<i class="fas fa-user" style="font-size:11px;"></i> User
|
||||
<span class="tab-count" id="count-user">{{ $user->where('role','user')->count() }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="table-responsive">
|
||||
<table class="table align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:40px;">#</th>
|
||||
<th>Nama</th>
|
||||
<th>Email</th>
|
||||
<th>Role</th>
|
||||
<th>Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@php $no = 1; @endphp
|
||||
@foreach($user as $u)
|
||||
@if($u->role != 'admin')
|
||||
<tr class="user-row" data-role="{{ $u->role }}">
|
||||
<td style="color:#9ca3af; font-weight:600;">{{ $no++ }}</td>
|
||||
<td class="nama-cell">{{ $u->name }}</td>
|
||||
<td class="email-cell">{{ $u->email }}</td>
|
||||
<td>
|
||||
@if($u->role == 'rt')
|
||||
<span class="badge-role badge-rt">rt</span>
|
||||
@else
|
||||
<span class="badge-role badge-user">user</span>
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
<div class="action-gap">
|
||||
<a href="{{ route('admin.user.edit', $u->id) }}" class="btn btn-edit">
|
||||
<i class="fas fa-edit" style="font-size:11px;"></i> Edit
|
||||
</a>
|
||||
<form action="{{ route('admin.user.delete', $u->id) }}" method="POST" style="display:inline;">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="btn btn-hapus" onclick="return confirm('Yakin hapus user ini?')">
|
||||
<i class="fas fa-trash" style="font-size:11px;"></i> Hapus
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@endif
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="pagination-wrap">
|
||||
<p class="pagination-info" id="paginationInfo"></p>
|
||||
<ul class="pagination" id="paginationControls"></ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const PER_PAGE = 10;
|
||||
let currentPage = 1;
|
||||
let activeFilter = 'all';
|
||||
|
||||
const allRows = Array.from(document.querySelectorAll('.user-row'));
|
||||
|
||||
function getVisibleRows() {
|
||||
return allRows.filter(row => {
|
||||
if (activeFilter === 'all') return true;
|
||||
return row.dataset.role === activeFilter;
|
||||
});
|
||||
}
|
||||
|
||||
function showPage(page) {
|
||||
currentPage = page;
|
||||
const visibleRows = getVisibleRows();
|
||||
const totalRows = visibleRows.length;
|
||||
const totalPages = Math.ceil(totalRows / PER_PAGE) || 1;
|
||||
|
||||
if (currentPage > totalPages) currentPage = totalPages;
|
||||
|
||||
const start = (currentPage - 1) * PER_PAGE;
|
||||
const end = start + PER_PAGE;
|
||||
|
||||
allRows.forEach(row => row.style.display = 'none');
|
||||
|
||||
visibleRows.forEach((row, i) => {
|
||||
row.style.display = (i >= start && i < end) ? '' : 'none';
|
||||
});
|
||||
|
||||
const from = totalRows === 0 ? 0 : start + 1;
|
||||
const to = Math.min(end, totalRows);
|
||||
document.getElementById('paginationInfo').textContent =
|
||||
totalRows === 0
|
||||
? 'Tidak ada data'
|
||||
: `Menampilkan ${from}–${to} dari ${totalRows} data`;
|
||||
|
||||
renderPagination(totalPages);
|
||||
}
|
||||
|
||||
function renderPagination(totalPages) {
|
||||
const ul = document.getElementById('paginationControls');
|
||||
ul.innerHTML = '';
|
||||
|
||||
const prevLi = document.createElement('li');
|
||||
prevLi.className = 'page-item' + (currentPage === 1 ? ' disabled' : '');
|
||||
prevLi.innerHTML = `<a class="page-link" href="#">‹</a>`;
|
||||
prevLi.addEventListener('click', e => { e.preventDefault(); if (currentPage > 1) showPage(currentPage - 1); });
|
||||
ul.appendChild(prevLi);
|
||||
|
||||
for (let i = 1; i <= totalPages; i++) {
|
||||
const li = document.createElement('li');
|
||||
li.className = 'page-item' + (i === currentPage ? ' active' : '');
|
||||
li.innerHTML = `<a class="page-link" href="#">${i}</a>`;
|
||||
li.addEventListener('click', e => { e.preventDefault(); showPage(i); });
|
||||
ul.appendChild(li);
|
||||
}
|
||||
|
||||
const nextLi = document.createElement('li');
|
||||
nextLi.className = 'page-item' + (currentPage === totalPages ? ' disabled' : '');
|
||||
nextLi.innerHTML = `<a class="page-link" href="#">›</a>`;
|
||||
nextLi.addEventListener('click', e => { e.preventDefault(); if (currentPage < totalPages) showPage(currentPage + 1); });
|
||||
ul.appendChild(nextLi);
|
||||
}
|
||||
|
||||
document.querySelectorAll('.filter-tab').forEach(tab => {
|
||||
tab.addEventListener('click', () => {
|
||||
document.querySelectorAll('.filter-tab').forEach(t => t.classList.remove('active'));
|
||||
tab.classList.add('active');
|
||||
activeFilter = tab.dataset.filter;
|
||||
currentPage = 1;
|
||||
showPage(1);
|
||||
});
|
||||
});
|
||||
|
||||
showPage(1);
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
|
|
@ -0,0 +1,391 @@
|
|||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
|
||||
{{-- HERO BANNER --}}
|
||||
<div class="profile-hero">
|
||||
<div class="profile-hero-icon">
|
||||
<i class="fas fa-user-cog"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="profile-hero-title">Pengaturan Akun</div>
|
||||
<div class="profile-hero-sub">Kelola informasi profil dan keamanan akun Anda</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="profile-wrap">
|
||||
|
||||
{{-- NOTIFIKASI --}}
|
||||
@if(session('success'))
|
||||
<div style="background:#f0fdf4; border:1px solid #bbf7d0; border-left:4px solid #064e3b;
|
||||
color:#065f46; border-radius:10px; padding:12px 16px; font-size:13px;
|
||||
font-weight:600; display:flex; align-items:center; gap:8px; margin-bottom:18px;">
|
||||
<i class="fas fa-check-circle"></i> {{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if($errors->any())
|
||||
<div style="background:#fef2f2; border:1px solid #fecaca; border-left:4px solid #dc2626;
|
||||
color:#dc2626; border-radius:10px; padding:12px 16px; font-size:13px;
|
||||
font-weight:600; margin-bottom:18px;">
|
||||
<i class="fas fa-exclamation-circle"></i>
|
||||
@foreach($errors->all() as $error)
|
||||
<div>{{ $error }}</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="profile-grid">
|
||||
|
||||
{{-- KOLOM KIRI --}}
|
||||
<div class="profile-left">
|
||||
|
||||
{{-- FOTO CARD --}}
|
||||
<div class="pcard">
|
||||
<div class="pcard-avatar-wrap">
|
||||
<img id="previewImg"
|
||||
src="{{ Auth::user()->photo
|
||||
? asset('profile/' . Auth::user()->photo) . '?' . time()
|
||||
: 'https://i.pravatar.cc/150?img=12' }}"
|
||||
class="pcard-avatar" alt="avatar">
|
||||
</div>
|
||||
<div class="pcard-name">{{ $user->name }}</div>
|
||||
<div class="pcard-email">{{ $user->email }}</div>
|
||||
|
||||
<form action="{{ route('rt.upload.photo') }}" method="POST"
|
||||
enctype="multipart/form-data" class="pcard-upload-form">
|
||||
@csrf
|
||||
<label class="btn-pilih-foto" for="fotoInput">
|
||||
<i class="fas fa-image me-1"></i> Pilih Foto
|
||||
</label>
|
||||
<input type="file" name="photo" id="fotoInput" accept="image/*" hidden>
|
||||
<button type="submit" class="btn-upload-foto">
|
||||
<i class="fas fa-cloud-upload-alt me-1"></i> Upload Foto
|
||||
</button>
|
||||
<div class="pcard-hint">JPG, PNG maks. 2MB</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{{-- INFO CARD --}}
|
||||
<div class="pcard pcard-info">
|
||||
<div class="pinfo-row">
|
||||
<div class="pinfo-icon"><i class="fas fa-user"></i></div>
|
||||
<div>
|
||||
<div class="pinfo-label">USERNAME</div>
|
||||
<div class="pinfo-value">{{ $user->username ?? $user->name }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pinfo-row">
|
||||
<div class="pinfo-icon pinfo-icon-blue"><i class="fas fa-envelope"></i></div>
|
||||
<div>
|
||||
<div class="pinfo-label">EMAIL</div>
|
||||
<div class="pinfo-value">{{ $user->email }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{{-- KOLOM KANAN --}}
|
||||
<div class="profile-right">
|
||||
<div class="pcard">
|
||||
|
||||
<div class="pform-header">
|
||||
<div class="pform-header-icon"><i class="fas fa-edit"></i></div>
|
||||
<div>
|
||||
<div class="pform-title">Edit Profil</div>
|
||||
<div class="pform-sub">Perbarui data diri Anda</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form action="{{ route('rt.updateprofile') }}" method="POST" id="profileForm">
|
||||
@csrf
|
||||
|
||||
<div class="pform-section-label">
|
||||
<i class="fas fa-user-circle me-1"></i> INFORMASI DASAR
|
||||
</div>
|
||||
|
||||
<div class="pform-row-2">
|
||||
<div class="pform-group">
|
||||
<label class="pform-label"><i class="fas fa-id-card me-1"></i> Nama Lengkap</label>
|
||||
<input type="text" name="name" class="pform-input" value="{{ $user->name }}">
|
||||
</div>
|
||||
<div class="pform-group">
|
||||
<label class="pform-label"><i class="fas fa-at me-1"></i> Username</label>
|
||||
<input type="text" name="username" class="pform-input" value="{{ $user->username ?? '' }}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pform-group">
|
||||
<label class="pform-label"><i class="fas fa-envelope me-1"></i> Alamat Email</label>
|
||||
<input type="email" name="email" class="pform-input" value="{{ $user->email }}">
|
||||
</div>
|
||||
|
||||
<div class="pform-section-label mt-2">
|
||||
<i class="fas fa-lock me-1"></i> KEAMANAN AKUN
|
||||
<span class="pform-section-hint">Kosongkan jika tidak ingin mengubah password</span>
|
||||
</div>
|
||||
|
||||
<div class="pform-row-2">
|
||||
<div class="pform-group">
|
||||
<label class="pform-label">Password Baru</label>
|
||||
<div class="pform-input-wrap">
|
||||
<input type="password" name="password" id="pw1" class="pform-input pform-input-icon" placeholder="Min. 8 karakter">
|
||||
<span class="pform-eye" onclick="togglePw('pw1', this)"><i class="fas fa-eye"></i></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pform-group">
|
||||
<label class="pform-label">Konfirmasi Password</label>
|
||||
<div class="pform-input-wrap">
|
||||
<input type="password" name="password_confirmation" id="pw2" class="pform-input pform-input-icon" placeholder="Ulangi password baru">
|
||||
<span class="pform-eye" onclick="togglePw('pw2', this)"><i class="fas fa-eye"></i></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pform-actions">
|
||||
<button type="reset" class="btn-reset">
|
||||
<i class="fas fa-undo me-1"></i> Reset
|
||||
</button>
|
||||
<button type="submit" class="btn-simpan">
|
||||
<i class="fas fa-check me-1"></i> Simpan Perubahan
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* =================================================
|
||||
WARNA UTAMA: #064e3b (hijau tua) — sama dgn Edit User
|
||||
================================================= */
|
||||
|
||||
.profile-hero {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 18px;
|
||||
background: linear-gradient(135deg, #064e3b 0%, #0a6b52 100%);
|
||||
border-radius: 16px;
|
||||
padding: 28px 32px;
|
||||
margin: 0 0 28px 0;
|
||||
box-shadow: 0 4px 20px rgba(6,78,59,0.2);
|
||||
}
|
||||
|
||||
.profile-hero-icon {
|
||||
width: 52px; height: 52px;
|
||||
background: rgba(255,255,255,0.12);
|
||||
border-radius: 14px;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
font-size: 22px; color: #fff; flex-shrink: 0;
|
||||
}
|
||||
|
||||
.profile-hero-title { font-size: 20px; font-weight: 800; color: #fff; line-height: 1.2; }
|
||||
.profile-hero-sub { font-size: 13px; color: rgba(255,255,255,0.65); margin-top: 3px; }
|
||||
|
||||
.profile-wrap { padding: 0; }
|
||||
|
||||
.profile-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 300px 1fr;
|
||||
gap: 24px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.pcard {
|
||||
background: #fff;
|
||||
border-radius: 16px;
|
||||
padding: 28px 24px;
|
||||
box-shadow: 0 2px 16px rgba(0,0,0,0.07);
|
||||
border: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.profile-left { display: flex; flex-direction: column; gap: 16px; }
|
||||
|
||||
.pcard-avatar-wrap { display: flex; justify-content: center; margin-bottom: 14px; }
|
||||
|
||||
.pcard-avatar {
|
||||
width: 110px; height: 110px;
|
||||
border-radius: 50%; object-fit: cover;
|
||||
border: 4px solid #a7f3d0;
|
||||
box-shadow: 0 4px 16px rgba(6,78,59,0.15);
|
||||
}
|
||||
|
||||
.pcard-name { text-align: center; font-size: 16px; font-weight: 700; color: #111827; }
|
||||
.pcard-email { text-align: center; font-size: 12.5px; color: #6b7280; margin-top: 3px; margin-bottom: 18px; }
|
||||
|
||||
.pcard-upload-form { display: flex; flex-direction: column; gap: 10px; }
|
||||
|
||||
.btn-pilih-foto {
|
||||
display: block; text-align: center; padding: 10px;
|
||||
border-radius: 10px; border: 2px dashed #6ee7b7;
|
||||
color: #064e3b; font-size: 13.5px; font-weight: 600;
|
||||
cursor: pointer; transition: all 0.2s; background: #f0fdf4;
|
||||
}
|
||||
.btn-pilih-foto:hover { background: #d1fae5; }
|
||||
|
||||
.btn-upload-foto {
|
||||
display: block; width: 100%; padding: 11px;
|
||||
border-radius: 10px;
|
||||
background: linear-gradient(135deg, #064e3b, #0d6e4f);
|
||||
color: #fff; font-size: 13.5px; font-weight: 700; border: none;
|
||||
cursor: pointer; box-shadow: 0 4px 12px rgba(6,78,59,0.25); transition: opacity 0.2s;
|
||||
}
|
||||
.btn-upload-foto:hover { opacity: 0.88; }
|
||||
|
||||
.pcard-hint { text-align: center; font-size: 11.5px; color: #9ca3af; }
|
||||
|
||||
.pcard-info { padding: 20px 24px; }
|
||||
|
||||
.pinfo-row {
|
||||
display: flex; align-items: center; gap: 14px;
|
||||
padding: 10px 0; border-bottom: 1px solid #f3f4f6;
|
||||
}
|
||||
.pinfo-row:last-child { border-bottom: none; }
|
||||
|
||||
.pinfo-icon {
|
||||
width: 36px; height: 36px; border-radius: 10px;
|
||||
background: #f0fdf4; display: flex; align-items: center;
|
||||
justify-content: center; color: #064e3b; font-size: 14px; flex-shrink: 0;
|
||||
}
|
||||
.pinfo-icon-blue { background: #eff6ff; color: #2563eb; }
|
||||
|
||||
.pinfo-label { font-size: 10px; font-weight: 700; color: #9ca3af; letter-spacing: 1px; text-transform: uppercase; }
|
||||
.pinfo-value { font-size: 13.5px; font-weight: 600; color: #111827; margin-top: 2px; }
|
||||
|
||||
.pform-header {
|
||||
display: flex; align-items: center; gap: 14px;
|
||||
margin-bottom: 24px; padding-bottom: 18px; border-bottom: 1px solid #f3f4f6;
|
||||
}
|
||||
|
||||
.pform-header-icon {
|
||||
width: 40px; height: 40px; background: #f0fdf4; border-radius: 10px;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
color: #064e3b; font-size: 16px; flex-shrink: 0;
|
||||
}
|
||||
|
||||
.pform-title { font-size: 16px; font-weight: 700; color: #111827; }
|
||||
.pform-sub { font-size: 12.5px; color: #6b7280; margin-top: 2px; }
|
||||
|
||||
.pform-section-label {
|
||||
font-size: 11px; font-weight: 800; color: #064e3b;
|
||||
letter-spacing: 1px; text-transform: uppercase;
|
||||
margin: 0 0 14px; display: flex; align-items: center; gap: 4px;
|
||||
}
|
||||
|
||||
.pform-section-hint {
|
||||
font-size: 11px; font-weight: 400; color: #9ca3af;
|
||||
letter-spacing: 0; text-transform: none; margin-left: auto;
|
||||
}
|
||||
|
||||
.pform-row-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 16px; }
|
||||
|
||||
.pform-group { display: flex; flex-direction: column; gap: 6px; margin-bottom: 16px; }
|
||||
.pform-row-2 .pform-group { margin-bottom: 0; }
|
||||
|
||||
.pform-label { font-size: 12.5px; font-weight: 600; color: #374151; }
|
||||
|
||||
.pform-input {
|
||||
padding: 11px 14px; border: 1.5px solid #e5e7eb; border-radius: 10px;
|
||||
font-size: 13.5px; color: #111827; background: #fafafa;
|
||||
transition: border 0.2s, box-shadow 0.2s; outline: none; width: 100%; box-sizing: border-box;
|
||||
}
|
||||
.pform-input:focus {
|
||||
border-color: #064e3b;
|
||||
box-shadow: 0 0 0 3px rgba(6,78,59,0.1);
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.pform-input-wrap { position: relative; }
|
||||
.pform-input-icon { padding-right: 42px; }
|
||||
|
||||
.pform-eye {
|
||||
position: absolute; right: 13px; top: 50%; transform: translateY(-50%);
|
||||
color: #9ca3af; cursor: pointer; font-size: 14px; transition: color 0.15s;
|
||||
}
|
||||
.pform-eye:hover { color: #064e3b; }
|
||||
|
||||
.pform-actions {
|
||||
display: flex; justify-content: flex-end; gap: 12px;
|
||||
margin-top: 8px; padding-top: 20px; border-top: 1px solid #f3f4f6;
|
||||
}
|
||||
|
||||
.btn-reset {
|
||||
padding: 11px 22px; border-radius: 10px; border: 1.5px solid #e5e7eb;
|
||||
background: #fff; color: #6b7280; font-size: 13.5px; font-weight: 600;
|
||||
cursor: pointer; transition: all 0.2s;
|
||||
}
|
||||
.btn-reset:hover { background: #f9fafb; border-color: #d1d5db; color: #374151; }
|
||||
|
||||
.btn-simpan {
|
||||
padding: 11px 28px; border-radius: 10px;
|
||||
background: linear-gradient(135deg, #064e3b, #0d6e4f);
|
||||
color: #fff; font-size: 13.5px; font-weight: 700; border: none;
|
||||
cursor: pointer; transition: opacity 0.2s;
|
||||
box-shadow: 0 4px 14px rgba(6,78,59,0.3);
|
||||
}
|
||||
.btn-simpan:hover { opacity: 0.88; }
|
||||
|
||||
/* ── MOBILE RESPONSIVE ── */
|
||||
@media (max-width: 768px) {
|
||||
.profile-hero {
|
||||
padding: 20px 18px;
|
||||
gap: 14px;
|
||||
border-radius: 12px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.profile-hero-title { font-size: 17px; }
|
||||
.profile-hero-sub { font-size: 12px; }
|
||||
|
||||
.profile-grid {
|
||||
grid-template-columns: 1fr; /* ← kolom jadi 1, stack ke bawah */
|
||||
}
|
||||
|
||||
.pform-row-2 {
|
||||
grid-template-columns: 1fr; /* ← 2 kolom form jadi 1 kolom */
|
||||
gap: 0;
|
||||
}
|
||||
.pform-row-2 .pform-group { margin-bottom: 16px; }
|
||||
|
||||
.pform-actions {
|
||||
flex-direction: column;
|
||||
}
|
||||
.btn-reset,
|
||||
.btn-simpan {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.pcard { padding: 20px 16px; }
|
||||
.pcard-info { padding: 16px; }
|
||||
|
||||
.pform-section-hint {
|
||||
display: block;
|
||||
margin-left: 0;
|
||||
margin-top: 4px;
|
||||
}
|
||||
.pform-section-label {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
document.getElementById('fotoInput').addEventListener('change', function(e) {
|
||||
if (e.target.files[0]) {
|
||||
document.getElementById('previewImg').src = URL.createObjectURL(e.target.files[0]);
|
||||
}
|
||||
});
|
||||
|
||||
function togglePw(id, el) {
|
||||
const input = document.getElementById(id);
|
||||
const isHidden = input.type === 'password';
|
||||
input.type = isHidden ? 'text' : 'password';
|
||||
el.innerHTML = isHidden ? '<i class="fas fa-eye-slash"></i>' : '<i class="fas fa-eye"></i>';
|
||||
}
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
|
|
@ -207,6 +207,21 @@
|
|||
display: block;
|
||||
}
|
||||
|
||||
/* ── MOBILE RESPONSIVE ── */
|
||||
.table-responsive-wrapper {
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.premium-table {
|
||||
min-width: 750px;
|
||||
}
|
||||
.page-header h1 { font-size: 18px; }
|
||||
.desc-text { max-width: 140px; }
|
||||
}
|
||||
|
||||
/* ── DATATABLES ── */
|
||||
.dataTables_wrapper { padding: 0; }
|
||||
.dataTables_wrapper .dataTables_length label,
|
||||
|
|
@ -326,8 +341,9 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="premium-card-body" style="padding: 0;">
|
||||
<table class="premium-table" id="dataTable" style="width:100%">
|
||||
<div class="premium-card-body" style="padding: 0;">
|
||||
<div class="table-responsive-wrapper">
|
||||
<table class="premium-table" id="dataTable" style="width:100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
|
|
@ -439,7 +455,8 @@
|
|||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</table>
|
||||
</div> {{-- tutup table-responsive-wrapper --}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@
|
|||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 16px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
|
@ -87,9 +87,8 @@
|
|||
}
|
||||
|
||||
.stat-card:nth-child(1) .stat-value { color: #111827; }
|
||||
.stat-card:nth-child(2) .stat-value { color: #6366f1; }
|
||||
.stat-card:nth-child(3) .stat-value { color: #064e3b; }
|
||||
.stat-card:nth-child(4) .stat-value { color: #f59e0b; }
|
||||
.stat-card:nth-child(2) .stat-value { color: #064e3b; }
|
||||
.stat-card:nth-child(3) .stat-value { color: #f59e0b; }
|
||||
|
||||
/* ── FILTER TABS ── */
|
||||
.filter-tabs {
|
||||
|
|
@ -142,17 +141,6 @@
|
|||
color: #fff;
|
||||
}
|
||||
|
||||
/* Admin tab */
|
||||
.filter-tab[data-filter="admin"].active {
|
||||
background: #eef2ff;
|
||||
color: #4f46e5;
|
||||
border-color: #a5b4fc;
|
||||
}
|
||||
.filter-tab[data-filter="admin"].active .tab-count {
|
||||
background: #c7d2fe;
|
||||
color: #4f46e5;
|
||||
}
|
||||
|
||||
/* RT tab */
|
||||
.filter-tab[data-filter="rt"].active {
|
||||
background: #fffbeb;
|
||||
|
|
@ -228,7 +216,6 @@
|
|||
text-transform: lowercase;
|
||||
}
|
||||
|
||||
.badge-admin { background: #eef2ff; color: #4f46e5; border: 1px solid #c7d2fe; }
|
||||
.badge-user { background: #f0fdf4; color: #064e3b; border: 1px solid #bbf7d0; }
|
||||
.badge-rt { background: #fffbeb; color: #d97706; border: 1px solid #fde68a; }
|
||||
|
||||
|
|
@ -268,22 +255,12 @@
|
|||
.btn-hapus { background: #fef2f2 !important; border: 1px solid #fecaca !important; color: #dc2626 !important; }
|
||||
.btn-hapus:hover { background: #fee2e2 !important; }
|
||||
|
||||
/* spacer between action buttons */
|
||||
.action-gap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.btn-disabled {
|
||||
background: #f3f4f6 !important;
|
||||
border: 1px solid #e5e7eb !important;
|
||||
color: #d1d5db !important;
|
||||
cursor: not-allowed !important;
|
||||
opacity: 0.6;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.pagination-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
@ -335,7 +312,6 @@
|
|||
gap: 8px;
|
||||
}
|
||||
|
||||
/* hide rows that don't match filter */
|
||||
.user-row.hidden-by-filter { display: none !important; }
|
||||
</style>
|
||||
|
||||
|
|
@ -356,15 +332,12 @@
|
|||
</a>
|
||||
</div>
|
||||
|
||||
{{-- STATS: hanya Total (rt+user), User, RT — admin disembunyikan --}}
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card">
|
||||
<p class="stat-value">{{ $user->count() }}</p>
|
||||
<p class="stat-value">{{ $user->whereIn('role', ['rt','user'])->count() }}</p>
|
||||
<p class="stat-label">Total User</p>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<p class="stat-value">{{ $user->where('role','admin')->count() }}</p>
|
||||
<p class="stat-label">Admin</p>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<p class="stat-value">{{ $user->where('role','user')->count() }}</p>
|
||||
<p class="stat-label">User</p>
|
||||
|
|
@ -381,15 +354,11 @@
|
|||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Filter Tabs --}}
|
||||
{{-- Filter Tabs: admin dihapus --}}
|
||||
<div class="filter-tabs">
|
||||
<button class="filter-tab active" data-filter="all">
|
||||
<i class="fas fa-users" style="font-size:11px;"></i> Semua
|
||||
<span class="tab-count" id="count-all">{{ $user->count() }}</span>
|
||||
</button>
|
||||
<button class="filter-tab" data-filter="admin">
|
||||
<i class="fas fa-user-shield" style="font-size:11px;"></i> Admin
|
||||
<span class="tab-count" id="count-admin">{{ $user->where('role','admin')->count() }}</span>
|
||||
<span class="tab-count" id="count-all">{{ $user->whereIn('role', ['rt','user'])->count() }}</span>
|
||||
</button>
|
||||
<button class="filter-tab" data-filter="rt">
|
||||
<i class="fas fa-home" style="font-size:11px;"></i> RT
|
||||
|
|
@ -414,44 +383,36 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($user as $index => $u)
|
||||
<tr class="user-row" data-role="{{ $u->role }}">
|
||||
<td style="color:#9ca3af; font-weight:600;">{{ $index + 1 }}</td>
|
||||
<td class="nama-cell">{{ $u->name }}</td>
|
||||
<td class="email-cell">{{ $u->email }}</td>
|
||||
<td>
|
||||
@if($u->role == 'admin')
|
||||
<span class="badge-role badge-admin">admin</span>
|
||||
@elseif($u->role == 'rt')
|
||||
<span class="badge-role badge-rt">rt</span>
|
||||
@else
|
||||
<span class="badge-role badge-user">user</span>
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
<div class="action-gap">
|
||||
{{-- Edit: disabled for admin --}}
|
||||
@if($u->role == 'admin')
|
||||
<button class="btn btn-edit btn-disabled" disabled title="Admin tidak dapat diedit">
|
||||
<i class="fas fa-edit" style="font-size:11px;"></i> Edit
|
||||
</button>
|
||||
@php $no = 1; @endphp
|
||||
@foreach($user as $u)
|
||||
@if($u->role != 'admin')
|
||||
<tr class="user-row" data-role="{{ $u->role }}">
|
||||
<td style="color:#9ca3af; font-weight:600;">{{ $no++ }}</td>
|
||||
<td class="nama-cell">{{ $u->name }}</td>
|
||||
<td class="email-cell">{{ $u->email }}</td>
|
||||
<td>
|
||||
@if($u->role == 'rt')
|
||||
<span class="badge-role badge-rt">rt</span>
|
||||
@else
|
||||
<span class="badge-role badge-user">user</span>
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
<div class="action-gap">
|
||||
<a href="{{ route('admin.user.edit', $u->id) }}" class="btn btn-edit">
|
||||
<i class="fas fa-edit" style="font-size:11px;"></i> Edit
|
||||
</a>
|
||||
@endif
|
||||
|
||||
{{-- Hapus --}}
|
||||
<form action="{{ route('admin.user.delete', $u->id) }}" method="POST" style="display:inline;">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="btn btn-hapus" onclick="return confirm('Yakin hapus user ini?')">
|
||||
<i class="fas fa-trash" style="font-size:11px;"></i> Hapus
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<form action="{{ route('admin.user.delete', $u->id) }}" method="POST" style="display:inline;">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="btn btn-hapus" onclick="return confirm('Yakin hapus user ini?')">
|
||||
<i class="fas fa-trash" style="font-size:11px;"></i> Hapus
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@endif
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
@ -485,16 +446,13 @@ function showPage(page) {
|
|||
const totalRows = visibleRows.length;
|
||||
const totalPages = Math.ceil(totalRows / PER_PAGE) || 1;
|
||||
|
||||
// Clamp page
|
||||
if (currentPage > totalPages) currentPage = totalPages;
|
||||
|
||||
const start = (currentPage - 1) * PER_PAGE;
|
||||
const end = start + PER_PAGE;
|
||||
|
||||
// Hide all first
|
||||
allRows.forEach(row => row.style.display = 'none');
|
||||
|
||||
// Show only current page of visible rows
|
||||
visibleRows.forEach((row, i) => {
|
||||
row.style.display = (i >= start && i < end) ? '' : 'none';
|
||||
});
|
||||
|
|
@ -534,7 +492,6 @@ function renderPagination(totalPages) {
|
|||
ul.appendChild(nextLi);
|
||||
}
|
||||
|
||||
// Filter tab logic
|
||||
document.querySelectorAll('.filter-tab').forEach(tab => {
|
||||
tab.addEventListener('click', () => {
|
||||
document.querySelectorAll('.filter-tab').forEach(t => t.classList.remove('active'));
|
||||
|
|
@ -545,7 +502,6 @@ function renderPagination(totalPages) {
|
|||
});
|
||||
});
|
||||
|
||||
// Init
|
||||
showPage(1);
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -328,6 +328,49 @@ class="pcard-avatar" alt="avatar">
|
|||
box-shadow: 0 4px 14px rgba(6,78,59,0.3);
|
||||
}
|
||||
.btn-simpan:hover { opacity: 0.88; }
|
||||
|
||||
/* ── MOBILE RESPONSIVE ── */
|
||||
@media (max-width: 768px) {
|
||||
.profile-hero {
|
||||
padding: 20px 18px;
|
||||
gap: 14px;
|
||||
border-radius: 12px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.profile-hero-title { font-size: 17px; }
|
||||
.profile-hero-sub { font-size: 12px; }
|
||||
|
||||
.profile-grid {
|
||||
grid-template-columns: 1fr; /* ← kolom jadi 1, stack ke bawah */
|
||||
}
|
||||
|
||||
.pform-row-2 {
|
||||
grid-template-columns: 1fr; /* ← 2 kolom form jadi 1 kolom */
|
||||
gap: 0;
|
||||
}
|
||||
.pform-row-2 .pform-group { margin-bottom: 16px; }
|
||||
|
||||
.pform-actions {
|
||||
flex-direction: column;
|
||||
}
|
||||
.btn-reset,
|
||||
.btn-simpan {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.pcard { padding: 20px 16px; }
|
||||
.pcard-info { padding: 16px; }
|
||||
|
||||
.pform-section-hint {
|
||||
display: block;
|
||||
margin-left: 0;
|
||||
margin-top: 4px;
|
||||
}
|
||||
.pform-section-label {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
|
|
|
|||
Loading…
Reference in New Issue