Kaynağa Gözat

fix: 🐛 Merge issues

IceToast 2 yıl önce
ebeveyn
işleme
255671e20d

+ 23 - 27
app/Http/Controllers/ServerController.php

@@ -33,7 +33,7 @@ class ServerController extends Controller
 
             //Get server infos from ptero
             $serverAttributes = Pterodactyl::getServerAttributes($server->pterodactyl_id, true);
-            if (! $serverAttributes) {
+            if (!$serverAttributes) {
                 continue;
             }
             $serverRelationships = $serverAttributes['relationships'];
@@ -70,7 +70,7 @@ class ServerController extends Controller
     /** Show the form for creating a new resource. */
     public function create()
     {
-        if (! is_null($this->validateConfigurationRules())) {
+        if (!is_null($this->validateConfigurationRules())) {
             return $this->validateConfigurationRules();
         }
 
@@ -125,7 +125,7 @@ class ServerController extends Controller
             // Check if node has enough memory and disk space
             $checkResponse = Pterodactyl::checkNodeResources($node, $product->memory, $product->disk);
             if ($checkResponse == false) {
-                return redirect()->route('servers.index')->with('error', __("The node '".$nodeName."' doesn't have the required memory or disk left to allocate this product."));
+                return redirect()->route('servers.index')->with('error', __("The node '" . $nodeName . "' doesn't have the required memory or disk left to allocate this product."));
             }
 
             // Min. Credits
@@ -133,23 +133,23 @@ class ServerController extends Controller
                 Auth::user()->credits < $product->minimum_credits ||
                 Auth::user()->credits < $product->price
             ) {
-                return redirect()->route('servers.index')->with('error', 'You do not have the required amount of '.CREDITS_DISPLAY_NAME.' to use this product!');
+                return redirect()->route('servers.index')->with('error', 'You do not have the required amount of ' . CREDITS_DISPLAY_NAME . ' to use this product!');
             }
         }
 
         //Required Verification for creating an server
-        if (config('SETTINGS::USER:FORCE_EMAIL_VERIFICATION', 'false') === 'true' && ! Auth::user()->hasVerifiedEmail()) {
+        if (config('SETTINGS::USER:FORCE_EMAIL_VERIFICATION', 'false') === 'true' && !Auth::user()->hasVerifiedEmail()) {
             return redirect()->route('profile.index')->with('error', __('You are required to verify your email address before you can create a server.'));
         }
 
         //Required Verification for creating an server
 
-        if (! config('SETTINGS::SYSTEM:CREATION_OF_NEW_SERVERS', 'true') && Auth::user()->role != 'admin') {
+        if (!config('SETTINGS::SYSTEM:CREATION_OF_NEW_SERVERS', 'true') && Auth::user()->role != 'admin') {
             return redirect()->route('servers.index')->with('error', __('The system administrator has blocked the creation of new servers.'));
         }
 
         //Required Verification for creating an server
-        if (config('SETTINGS::USER:FORCE_DISCORD_VERIFICATION', 'false') === 'true' && ! Auth::user()->discordUser) {
+        if (config('SETTINGS::USER:FORCE_DISCORD_VERIFICATION', 'false') === 'true' && !Auth::user()->discordUser) {
             return redirect()->route('profile.index')->with('error', __('You are required to link your discord account before you can create a server.'));
         }
 
@@ -162,7 +162,7 @@ class ServerController extends Controller
         /** @var Node $node */
         /** @var Egg $egg */
         /** @var Product $product */
-        if (! is_null($this->validateConfigurationRules())) {
+        if (!is_null($this->validateConfigurationRules())) {
             return $this->validateConfigurationRules();
         }
 
@@ -186,7 +186,7 @@ class ServerController extends Controller
 
         //get free allocation ID
         $allocationId = Pterodactyl::getFreeAllocationId($node);
-        if (! $allocationId) {
+        if (!$allocationId) {
             return $this->noAllocationsError($server);
         }
 
@@ -249,13 +249,9 @@ class ServerController extends Controller
     }
 
     /** Cancel Server */
-    public function cancel (Server $server)
+    public function cancel(Server $server)
     {
         try {
-            error_log($server->update([
-                'cancelled' => now(),
-            ]));
-
             return redirect()->route('servers.index')->with('success', __('Server cancelled'));
         } catch (Exception $e) {
             return redirect()->route('servers.index')->with('error', __('An exception has occurred while trying to cancel the server"') . $e->getMessage() . '"');
@@ -267,7 +263,9 @@ class ServerController extends Controller
     {
 
 
-        if($server->user_id != Auth::user()->id){ return back()->with('error', __('This is not your Server!'));}
+        if ($server->user_id != Auth::user()->id) {
+            return back()->with('error', __('This is not your Server!'));
+        }
         $serverAttributes = Pterodactyl::getServerAttributes($server->pterodactyl_id);
         $serverRelationships = $serverAttributes['relationships'];
         $serverLocationAttributes = $serverRelationships['location']['attributes'];
@@ -287,10 +285,10 @@ class ServerController extends Controller
         $pteroNode = Pterodactyl::getNode($serverRelationships['node']['attributes']['id']);
 
         $products = Product::orderBy('created_at')
-        ->whereHas('nodes', function (Builder $builder) use ($serverRelationships) { //Only show products for that node
-            $builder->where('id', '=', $serverRelationships['node']['attributes']['id']);
-        })
-        ->get();
+            ->whereHas('nodes', function (Builder $builder) use ($serverRelationships) { //Only show products for that node
+                $builder->where('id', '=', $serverRelationships['node']['attributes']['id']);
+            })
+            ->get();
 
         // Set the each product eggs array to just contain the eggs name
         foreach ($products as $product) {
@@ -308,9 +306,8 @@ class ServerController extends Controller
 
     public function upgrade(Server $server, Request $request)
     {
-        if($server->user_id != Auth::user()->id || $server->suspended) return redirect()->route('servers.index');
-        if(!isset($request->product_upgrade))
-        {
+        if ($server->user_id != Auth::user()->id || $server->suspended) return redirect()->route('servers.index');
+        if (!isset($request->product_upgrade)) {
             return redirect()->route('servers.show', ['server' => $server->id])->with('error', __('this product is the only one'));
         }
         $user = Auth::user();
@@ -329,7 +326,7 @@ class ServerController extends Controller
         $requiredisk = $newProduct->disk - $oldProduct->disk;
         $checkResponse = Pterodactyl::checkNodeResources($node, $requireMemory, $requiredisk);
         if ($checkResponse == false) {
-            return redirect()->route('servers.index')->with('error', __("The node '".$nodeName."' doesn't have the required memory or disk left to upgrade the server."));
+            return redirect()->route('servers.index')->with('error', __("The node '" . $nodeName . "' doesn't have the required memory or disk left to upgrade the server."));
         }
 
         // calculate the amount of credits that the user overpayed for the old product when canceling the server right now
@@ -353,8 +350,7 @@ class ServerController extends Controller
         $overpayedCredits = $oldProduct->price - $oldProduct->price * ($timeDifference / $billingPeriodMultiplier);
 
 
-        if ($user->credits >= $newProduct->price && $user->credits >= $newProduct->minimum_credits)
-        {
+        if ($user->credits >= $newProduct->price && $user->credits >= $newProduct->minimum_credits) {
             $server->allocation = $serverAttributes['allocation'];
             // Update the server on the panel
             $response = Pterodactyl::updateServer($server, $newProduct);
@@ -374,11 +370,11 @@ class ServerController extends Controller
             if ($overpayedCredits > 0) $user->increment('credits', $overpayedCredits);
 
             // Withdraw the credits for the new product
-            $user->decrement('credits', $newProduct->price); 
+            $user->decrement('credits', $newProduct->price);
 
             //restart the server
             $response = Pterodactyl::powerAction($server, "restart");
-            if ($response->failed()) return redirect()->route('servers.index')->with('error', 'Server upgraded successfully! Could not restart the server:   '.$response->json()['errors'][0]['detail']);
+            if ($response->failed()) return redirect()->route('servers.index')->with('error', 'Server upgraded successfully! Could not restart the server:   ' . $response->json()['errors'][0]['detail']);
             return redirect()->route('servers.show', ['server' => $server->id])->with('success', __('Server Successfully Upgraded'));
         } else {
             return redirect()->route('servers.show', ['server' => $server->id])->with('error', __('Not Enough Balance for Upgrade'));

+ 4 - 9
app/Models/User.php

@@ -185,7 +185,7 @@ class User extends Authenticatable implements MustVerifyEmail
     }
 
     /**
-     * @throws Exception
+     * @throws \Exception
      */
     public function suspend()
     {
@@ -201,7 +201,7 @@ class User extends Authenticatable implements MustVerifyEmail
     }
 
     /**
-     * @throws Exception
+     * @throws \Exception
      */
     public function unSuspend()
     {
@@ -218,12 +218,6 @@ class User extends Authenticatable implements MustVerifyEmail
         return $this;
     }
 
-    private function getServersWithProduct()
-    {
-        return $this->servers()
-            ->with('product')
-            ->get();
-    }
 
     /**
      * @return string
@@ -257,7 +251,8 @@ class User extends Authenticatable implements MustVerifyEmail
         return number_format($usage, 2, '.', '');
     }
 
-    private function getServersWithProduct() {
+    private function getServersWithProduct()
+    {
         return $this->servers()
             ->whereNull('suspended')
             ->whereNull('cancelled')

+ 0 - 295
resources/views/servers/index.blade.php

@@ -1,295 +0,0 @@
-@extends('layouts.main')
-
-@section('content')
-    <!-- CONTENT HEADER -->
-    <section class="content-header">
-        <div class="container-fluid">
-            <div class="row mb-2">
-                <div class="col-sm-6">
-                    <h1>{{ __('Servers') }}</h1>
-                </div>
-                <div class="col-sm-6">
-                    <ol class="breadcrumb float-sm-right">
-                        <li class="breadcrumb-item"><a href="{{ route('home') }}">{{ __('Dashboard') }}</a></li>
-                        <li class="breadcrumb-item"><a class="text-muted"
-                                href="{{ route('servers.index') }}">{{ __('Servers') }}</a>
-                        </li>
-                    </ol>
-                </div>
-            </div>
-        </div>
-    </section>
-    <!-- END CONTENT HEADER -->
-
-    <!-- MAIN CONTENT -->
-    <section class="content">
-        <div class="container-fluid">
-
-            <!-- CUSTOM CONTENT -->
-            <div class="d-flex justify-content-md-start justify-content-center mb-3 ">
-                <a @if (Auth::user()->Servers->count() >= Auth::user()->server_limit)
-                    disabled="disabled" title="Server limit reached!"
-                    @endif href="{{ route('servers.create') }}"
-                    class="btn
-                    @if (Auth::user()->Servers->count() >= Auth::user()->server_limit) disabled
-                    @endif btn-primary"><i
-                        class="fa fa-plus mr-2"></i>
-                    {{ __('Create Server') }}
-                </a>
-            </div>
-
-            <div class="row d-flex flex-row justify-content-center justify-content-md-start">
-                @foreach ($servers as $server)
-                    <div class="col-xl-3 col-lg-5 col-md-6 col-sm-6 col-xs-12 card pr-0 pl-0 ml-sm-2 mr-sm-3"
-                        style="max-width: 350px">
-                        <div class="card-header">
-                            <div class="d-flex justify-content-between align-items-center">
-                                <h5 class="card-title mt-1">{{ $server->name }}
-                                </h5>
-                                <div class="card-tools mt-1">
-                                    <div class="dropdown no-arrow">
-                                        <a href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown"
-                                            aria-haspopup="true" aria-expanded="false">
-                                            <i class="fas fa-ellipsis-v fa-sm fa-fw text-white-50"></i>
-                                        </a>
-                                        <div class="dropdown-menu dropdown-menu-right shadow animated--fade-in"
-                                            aria-labelledby="dropdownMenuLink">
-                                            @if (!empty(config('SETTINGS::MISC:PHPMYADMIN:URL')))
-                                                <a href="{{ config('SETTINGS::MISC:PHPMYADMIN:URL') }}"
-                                                    class="dropdown-item text-info" target="__blank"><i title="manage"
-                                                        class="fas fa-database mr-2"></i><span>{{ __('Database') }}</span></a>
-                                            @endif
-                                            <div class="dropdown-divider"></div>
-                                            <span class="dropdown-item"><i title="Created at"
-                                                    class="fas fa-sync-alt mr-2"></i><span>{{ $server->created_at->isoFormat('LL') }}</span></span>
-                                        </div>
-                                    </div>
-                                </div>
-                            </div>
-                        </div>
-                        <div class="card-body">
-                            <div class="container mt-1">
-                                <div class="row mb-3">
-                                    <div class="col my-auto">{{ __('Status') }}:</div>
-                                    <div class="col-7 my-auto">
-                                        @if($server->suspended)
-                                            <span class="badge badge-danger">{{ __('Suspended') }}</span>
-                                        @elseif($server->cancelled)
-                                            <span class="badge badge-warning">{{ __('Cancelled') }}</span>
-                                        @else
-                                            <span class="badge badge-success">{{ __('Active') }}</span>
-                                        @endif
-                                    </div>
-                                </div>
-                                <div class="row mb-2">
-                                    <div class="col-5">
-                                        {{ __('Location') }}:
-                                    </div>
-                                    <div class="col-7 d-flex justify-content-between align-items-center">
-                                        <span class="">{{ $server->location }}</span>
-                                        <i data-toggle="popover" data-trigger="hover"
-                                            data-content="{{ __('Node') }}: {{ $server->node }}"
-                                            class="fas fa-info-circle"></i>
-                                    </div>
-
-                                </div>
-                                <div class="row mb-2">
-                                    <div class="col-5 ">
-                                        {{ __('Software') }}:
-                                    </div>
-                                    <div class="col-7 text-wrap">
-                                        <span>{{ $server->nest }}</span>
-                                    </div>
-
-                                </div>
-                                <div class="row mb-2">
-                                    <div class="col-5 ">
-                                        {{ __('Specification') }}:
-                                    </div>
-                                    <div class="col-7 text-wrap">
-                                        <span>{{ $server->egg }}</span>
-                                    </div>
-                                </div>
-                                <div class="row mb-2">
-                                    <div class="col-5 ">
-                                        {{ __('Resource plan') }}:
-                                    </div>
-                                    <div class="col-7 text-wrap d-flex justify-content-between align-items-center">
-                                        <span>{{ $server->product->name }}
-                                        </span>
-                                        <i data-toggle="popover" data-trigger="hover" data-html="true"
-                                            data-content="{{ __('CPU') }}: {{ $server->product->cpu / 100 }} {{ __('vCores') }} <br/>{{ __('RAM') }}: {{ $server->product->memory }} MB <br/>{{ __('Disk') }}: {{ $server->product->disk }} MB <br/>{{ __('Backups') }}: {{ $server->product->backups }} <br/> {{ __('MySQL Databases') }}: {{ $server->product->databases }} <br/> {{ __('Allocations') }}: {{ $server->product->allocations }} <br/> {{ __('Billing Period') }}: {{$server->product->billing_period}}"
-                                            class="fas fa-info-circle"></i>
-                                    </div>
-                                </div>
-
-                                <div class="row mb-4 ">
-                                    <div class="col-5 word-break" style="hyphens: auto">
-                                        {{ __('Next Billing Cycle') }}:
-                                    </div>
-                                    <div class="col-7 d-flex text-wrap align-items-center">
-                                        <span>
-                                        @if ($server->suspended)
-                                            -
-                                        @else
-                                            @switch($server->product->billing_period)
-                                                @case('monthly')
-                                                    {{ \Carbon\Carbon::parse($server->last_billed)->addMonth()->toDayDateTimeString(); }}
-                                                    @break
-                                                @case('weekly')
-                                                    {{ \Carbon\Carbon::parse($server->last_billed)->addWeek()->toDayDateTimeString(); }}
-                                                    @break
-                                                @case('daily')
-                                                    {{ \Carbon\Carbon::parse($server->last_billed)->addDay()->toDayDateTimeString(); }}
-                                                    @break
-                                                @case('hourly')
-                                                    {{ \Carbon\Carbon::parse($server->last_billed)->addHour()->toDayDateTimeString(); }}
-                                                    @break
-                                                @case('quarterly')
-                                                    {{ \Carbon\Carbon::parse($server->last_billed)->addMonths(3)->toDayDateTimeString(); }}
-                                                    @break
-                                                @case('half-annually')
-                                                    {{ \Carbon\Carbon::parse($server->last_billed)->addMonths(6)->toDayDateTimeString(); }}
-                                                    @break
-                                                @case('annually')
-                                                    {{ \Carbon\Carbon::parse($server->last_billed)->addYear()->toDayDateTimeString(); }}
-                                                    @break
-                                                @default
-                                                    {{ __('Unknown') }}
-                                            @endswitch
-                                        @endif
-                                        </span>
-                                    </div>
-                                </div>
-
-                                <div class="row mb-2">
-                                    <div class="col-4">
-                                        {{ __('Price') }}:
-                                        <span class="text-muted">
-                                            ({{ CREDITS_DISPLAY_NAME }})
-                                        </span>
-                                    </div>
-                                    <div class="col-8 text-center">
-                                        <div class="text-muted">
-                                        @if($server->product->billing_period == 'monthly')
-                                            {{ __('per Month') }}
-                                        @elseif($server->product->billing_period == 'half-annually')
-                                            {{ __('per 6 Months') }}
-                                        @elseif($server->product->billing_period == 'quarterly')
-                                            {{ __('per 3 Months') }}
-                                        @elseif($server->product->billing_period == 'annually')
-                                            {{ __('per Year') }}
-                                        @elseif($server->product->billing_period == 'weekly')
-                                            {{ __('per Week') }}
-                                        @elseif($server->product->billing_period == 'daily')
-                                            {{ __('per Day') }}
-                                        @elseif($server->product->billing_period == 'hourly')
-                                            {{ __('per Hour') }}
-                                        @endif
-                                            </div>
-                                        <span>
-                                            {{ $server->product->price == round($server->product->price) ? round($server->product->price) : $server->product->price }}
-                                        </span>
-                                    </div>
-                                </div>
-                            </div>
-                        </div>
-
-                        <div class="card-footer text-center">
-                            <a href="{{ config('SETTINGS::SYSTEM:PTERODACTYL:URL') }}/server/{{ $server->identifier }}"
-                                target="__blank"
-                                class="btn btn-info text-center float-left ml-2"
-                                data-toggle="tooltip" data-placement="bottom" title="{{ __('Manage Server') }}">
-                                <i class="fas fa-tools mx-2"></i>
-                            </a>
-                            @if(config("SETTINGS::SYSTEM:PTERODACTYL:ADMIN_USER_TOKEN"))
-                            <a href="{{ route('servers.show', ['server' => $server->id])}}"
-                            	class="btn btn-info text-center mr-3"
-                            	data-toggle="tooltip" data-placement="bottom" title="{{ __('Server Settings') }}">
-                                <i class="fas fa-cog mx-2"></i>
-                            </a>
-                            @endif
-                            <button onclick="handleServerCancel('{{ $server->id }}');" target="__blank"
-                                class="btn btn-warning  text-center"
-                                {{ $server->suspended || $server->cancelled ? "disabled" : "" }}
-                                data-toggle="tooltip" data-placement="bottom" title="{{ __('Cancel Server') }}">
-                                <i class="fas fa-ban mx-2"></i>
-                            </button>
-                            <button onclick="handleServerDelete('{{ $server->id }}');" target="__blank"
-                                class="btn btn-danger  text-center float-right mr-2"
-                                data-toggle="tooltip" data-placement="bottom" title="{{ __('Delete Server') }}">
-                                <i class="fas fa-trash mx-2"></i>
-                            </button>
-                        </div>
-                    </div>
-                @endforeach
-            </div>
-            <!-- END CUSTOM CONTENT -->
-        </div>
-    </section>
-    <!-- END CONTENT -->
-
-    <script>
-        const handleServerCancel = (serverId) => {
-            // Handle server cancel with sweetalert
-            Swal.fire({
-                title: "{{ __('Cancel Server?') }}",
-                text: "{{ __('This will cancel your current server to the next billing period. It will get suspended when the current period runs out.') }}",
-                icon: 'warning',
-                confirmButtonColor: '#d9534f',
-                showCancelButton: true,
-                confirmButtonText: "{{ __('Yes, cancel it!') }}",
-                cancelButtonText: "{{ __('No, abort!') }}",
-                reverseButtons: true
-            }).then((result) => {
-                if (result.value) {
-                    // Delete server
-                    fetch("{{ route('servers.cancel', '') }}" + '/' + serverId, {
-                        method: 'PATCH',
-                        headers: {
-                            'X-CSRF-TOKEN': '{{ csrf_token() }}'
-                        }
-                    }).then(() => {
-                        window.location.reload();
-                    });
-                    return
-                }
-            })
-        }
-
-        const handleServerDelete = (serverId) => {
-            Swal.fire({
-                title: "{{ __('Delete Server?') }}",
-                html: "{{!! __('This is an irreversible action, all files of this server will be removed. <strong>No funds will get refunded</strong>. We recommend deleting the server when server is suspended.') !!}}",
-                icon: 'warning',
-                confirmButtonColor: '#d9534f',
-                showCancelButton: true,
-                confirmButtonText: "{{ __('Yes, delete it!') }}",
-                cancelButtonText: "{{ __('No, abort!') }}",
-                reverseButtons: true
-            }).then((result) => {
-                if (result.value) {
-                    // Delete server
-                    fetch("{{ route('servers.destroy', '') }}" + '/' + serverId, {
-                        method: 'DELETE',
-                        headers: {
-                            'X-CSRF-TOKEN': '{{ csrf_token() }}'
-                        }
-                    }).then(() => {
-                        window.location.reload();
-                    });
-                    return
-                }
-            });
-
-        }
-
-        document.addEventListener('DOMContentLoaded', () => {
-            $('[data-toggle="popover"]').popover();
-        });
-
-        $(function () {
-            $('[data-toggle="tooltip"]').tooltip()
-        })
-    </script>
-@endsection

+ 12 - 10
themes/default/views/servers/create.blade.php

@@ -213,11 +213,11 @@
 
                                                     <span class="d-inline-block" x-text="product.billing_period"></span>
                                                 </li>
-                                                <li>
+                                                <li class="d-flex justify-content-between">
                                                     <span class="d-inline-block"><i class="fa fa-coins"></i>
                                                         {{ __('Minimum') }} {{ CREDITS_DISPLAY_NAME }}</span>
                                                     <span class="d-inline-block"
-                                                        x-text="product.minimum_credits == -1 ? {{ config('SETTINGS::USER:MINIMUM_REQUIRED_CREDITS_TO_MAKE_SERVER') }} : product.minimum_credits"></span>
+                                                        x-text="product.minimum_credits == -1 ? {{ config('SETTINGS::USER:MINIMUM_REQUIRED_CREDITS_TO_MAKE_SERVER') }} : Math.round(product.minimum_credits)"></span>
                                                 </li>
                                             </ul>
                                         </div>
@@ -240,14 +240,16 @@
                                         <input type="hidden" name="product" x-model="selectedProduct">
                                     </div>
                                     <div>
-										<button type="submit" x-model="selectedProduct" name="product"
-        									:disabled="product.minimum_credits > user.credits || product.price > user.credits || product.doesNotFit == true ||
-            									submitClicked"
-       										:class="product.minimum_credits > user.credits || product.price > user.credits || product.doesNotFit == true ||
-            									submitClicked ? 'disabled' : ''"
-        									class="btn btn-primary btn-block mt-2" @click="setProduct(product.id);"
-        									x-text="product.doesNotFit == true ? '{{ __('Server cant fit on this Node') }}' : (product.minimum_credits > user.credits || product.price > user.credits ? '{{ __('Not enough') }} {{ CREDITS_DISPLAY_NAME }}!' : '{{ __('Create server') }}')">
-    									</button>
+                                        <button type="submit" x-model="selectedProduct" name="product"
+                                            :disabled="product.minimum_credits > user.credits || product.price > user.credits ||
+                                                product.doesNotFit == true ||
+                                                submitClicked"
+                                            :class="product.minimum_credits > user.credits || product.price > user.credits ||
+                                                product.doesNotFit == true ||
+                                                submitClicked ? 'disabled' : ''"
+                                            class="btn btn-primary btn-block mt-2" @click="setProduct(product.id);"
+                                            x-text="product.doesNotFit == true ? '{{ __('Server cant fit on this Node') }}' : (product.minimum_credits > user.credits || product.price > user.credits ? '{{ __('Not enough') }} {{ CREDITS_DISPLAY_NAME }}!' : '{{ __('Create server') }}')">
+                                        </button>
                                     </div>
                                 </div>
                             </div>

+ 230 - 94
themes/default/views/servers/index.blade.php

@@ -36,124 +36,260 @@
                         class="fa fa-plus mr-2"></i>
                     {{ __('Create Server') }}
                 </a>
-                @if (Auth::user()->Servers->count() > 0&&!empty(config('SETTINGS::MISC:PHPMYADMIN:URL')))
-                    <a 
-                        href="{{ config('SETTINGS::MISC:PHPMYADMIN:URL') }}" target="_blank"
-                        class="btn btn-secondary ml-2"><i title="manage"
-                        class="fas fa-database mr-2"></i><span>{{ __('Database') }}</span>
-                    </a>
-                @endif
             </div>
 
             <div class="row d-flex flex-row justify-content-center justify-content-md-start">
                 @foreach ($servers as $server)
-                    @if($server->location&&$server->node&&$server->nest&&$server->egg)
-                        <div class="col-xl-3 col-lg-5 col-md-6 col-sm-6 col-xs-12 card pr-0 pl-0 ml-sm-2 mr-sm-3"
-                            style="max-width: 350px">
-                            <div class="card-header">
-                                <div class="d-flex justify-content-between align-items-center">
-                                    <h5 class="card-title mt-1">{{ $server->name }}
-                                    </h5>
+                    <div class="col-xl-3 col-lg-5 col-md-6 col-sm-6 col-xs-12 card pr-0 pl-0 ml-sm-2 mr-sm-3"
+                        style="max-width: 350px">
+                        <div class="card-header">
+                            <div class="d-flex justify-content-between align-items-center">
+                                <h5 class="card-title mt-1">{{ $server->name }}
+                                </h5>
+                                <div class="card-tools mt-1">
+                                    <div class="dropdown no-arrow">
+                                        <a href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown"
+                                            aria-haspopup="true" aria-expanded="false">
+                                            <i class="fas fa-ellipsis-v fa-sm fa-fw text-white-50"></i>
+                                        </a>
+                                        <div class="dropdown-menu dropdown-menu-right shadow animated--fade-in"
+                                            aria-labelledby="dropdownMenuLink">
+                                            @if (!empty(config('SETTINGS::MISC:PHPMYADMIN:URL')))
+                                                <a href="{{ config('SETTINGS::MISC:PHPMYADMIN:URL') }}"
+                                                    class="dropdown-item text-info" target="__blank"><i title="manage"
+                                                        class="fas fa-database mr-2"></i><span>{{ __('Database') }}</span></a>
+                                            @endif
+                                            <div class="dropdown-divider"></div>
+                                            <span class="dropdown-item"><i title="Created at"
+                                                    class="fas fa-sync-alt mr-2"></i><span>{{ $server->created_at->isoFormat('LL') }}</span></span>
+                                        </div>
+                                    </div>
                                 </div>
                             </div>
-                            <div class="card-body">
-                                <div class="container mt-1">
-                                    <div class="row mb-3">
-                                        <div class="col my-auto">{{ __('Status') }}:</div>
-                                        <div class="col-7 my-auto">
-                                            <i
-                                                class="fas {{ $server->isSuspended() ? 'text-danger' : 'text-success' }} fa-circle mr-2"></i>
-                                            {{ $server->isSuspended() ? 'Suspended' : 'Active' }}
-                                        </div>
+                        </div>
+                        <div class="card-body">
+                            <div class="container mt-1">
+                                <div class="row mb-3">
+                                    <div class="col my-auto">{{ __('Status') }}:</div>
+                                    <div class="col-7 my-auto">
+                                        @if($server->suspended)
+                                            <span class="badge badge-danger">{{ __('Suspended') }}</span>
+                                        @elseif($server->cancelled)
+                                            <span class="badge badge-warning">{{ __('Cancelled') }}</span>
+                                        @else
+                                            <span class="badge badge-success">{{ __('Active') }}</span>
+                                        @endif
+                                    </div>
+                                </div>
+                                <div class="row mb-2">
+                                    <div class="col-5">
+                                        {{ __('Location') }}:
+                                    </div>
+                                    <div class="col-7 d-flex justify-content-between align-items-center">
+                                        <span class="">{{ $server->location }}</span>
+                                        <i data-toggle="popover" data-trigger="hover"
+                                            data-content="{{ __('Node') }}: {{ $server->node }}"
+                                            class="fas fa-info-circle"></i>
                                     </div>
-                                    <div class="row mb-2">
-                                        <div class="col-5">
-                                            {{ __('Location') }}:
-                                        </div>
-                                        <div class="col-7 d-flex justify-content-between align-items-center">
-                                            <span class="">{{ $server->location }}</span>
-                                            <i data-toggle="popover" data-trigger="hover"
-                                                data-content="{{ __('Node') }}: {{ $server->node }}"
-                                                class="fas fa-info-circle"></i>
-                                        </div>
 
+                                </div>
+                                <div class="row mb-2">
+                                    <div class="col-5 ">
+                                        {{ __('Software') }}:
+                                    </div>
+                                    <div class="col-7 text-wrap">
+                                        <span>{{ $server->nest }}</span>
                                     </div>
-                                    <div class="row mb-2">
-                                        <div class="col-5 ">
-                                            {{ __('Software') }}:
-                                        </div>
-                                        <div class="col-7 text-wrap">
-                                            <span>{{ $server->nest }}</span>
-                                        </div>
 
+                                </div>
+                                <div class="row mb-2">
+                                    <div class="col-5 ">
+                                        {{ __('Specification') }}:
                                     </div>
-                                    <div class="row mb-2">
-                                        <div class="col-5 ">
-                                            {{ __('Specification') }}:
-                                        </div>
-                                        <div class="col-7 text-wrap">
-                                            <span>{{ $server->egg }}</span>
-                                        </div>
+                                    <div class="col-7 text-wrap">
+                                        <span>{{ $server->egg }}</span>
                                     </div>
-                                    <div class="row mb-4">
-                                        <div class="col-5 ">
-                                            {{ __('Resource plan') }}:
-                                        </div>
-                                        <div class="col-7 text-wrap d-flex justify-content-between align-items-center">
-                                            <span>{{ $server->product->name }}
-                                            </span>
-                                            <i data-toggle="popover" data-trigger="hover" data-html="true"
-                                                data-content="{{ __('CPU') }}: {{ $server->product->cpu / 100 }} {{ __('vCores') }} <br/>{{ __('RAM') }}: {{ $server->product->memory }} MB <br/>{{ __('Disk') }}: {{ $server->product->disk }} MB <br/>{{ __('Backups') }}: {{ $server->product->backups }} <br/> {{ __('MySQL Databases') }}: {{ $server->product->databases }} <br/> {{ __('Allocations') }}: {{ $server->product->allocations }} <br/>"
-                                                class="fas fa-info-circle"></i>
-                                        </div>
+                                </div>
+                                <div class="row mb-2">
+                                    <div class="col-5 ">
+                                        {{ __('Resource plan') }}:
+                                    </div>
+                                    <div class="col-7 text-wrap d-flex justify-content-between align-items-center">
+                                        <span>{{ $server->product->name }}
+                                        </span>
+                                        <i data-toggle="popover" data-trigger="hover" data-html="true"
+                                            data-content="{{ __('CPU') }}: {{ $server->product->cpu / 100 }} {{ __('vCores') }} <br/>{{ __('RAM') }}: {{ $server->product->memory }} MB <br/>{{ __('Disk') }}: {{ $server->product->disk }} MB <br/>{{ __('Backups') }}: {{ $server->product->backups }} <br/> {{ __('MySQL Databases') }}: {{ $server->product->databases }} <br/> {{ __('Allocations') }}: {{ $server->product->allocations }} <br/> {{ __('Billing Period') }}: {{$server->product->billing_period}}"
+                                            class="fas fa-info-circle"></i>
+                                    </div>
+                                </div>
 
+                                <div class="row mb-4 ">
+                                    <div class="col-5 word-break" style="hyphens: auto">
+                                        {{ __('Next Billing Cycle') }}:
                                     </div>
-                                    <div class="row mb-2">
-                                        <div class="col-4">
-                                            {{ __('Price') }}:
-                                            <span class="text-muted">
-                                                ({{ CREDITS_DISPLAY_NAME }})
-                                            </span>
-                                        </div>
-                                        <div class="col-8">
-                                            <div class="row">
-                                                <div class="col-6  text-center">
-                                                    <div class="text-muted">{{ __('per Hour') }}</div>
-                                                    <span>
-                                                        {{ number_format($server->product->getHourlyPrice(), 2, '.', '') }}
-                                                    </span>
-                                                </div>
-                                                <div class="col-6  text-center">
-                                                    <div class="text-muted">{{ __('per Month') }}
-                                                    </div>
-                                                    <span>
-                                                        {{ $server->product->getHourlyPrice() * 24 * 30 }}
-                                                    </span>
-                                                </div>
+                                    <div class="col-7 d-flex text-wrap align-items-center">
+                                        <span>
+                                        @if ($server->suspended)
+                                            -
+                                        @else
+                                            @switch($server->product->billing_period)
+                                                @case('monthly')
+                                                    {{ \Carbon\Carbon::parse($server->last_billed)->addMonth()->toDayDateTimeString(); }}
+                                                    @break
+                                                @case('weekly')
+                                                    {{ \Carbon\Carbon::parse($server->last_billed)->addWeek()->toDayDateTimeString(); }}
+                                                    @break
+                                                @case('daily')
+                                                    {{ \Carbon\Carbon::parse($server->last_billed)->addDay()->toDayDateTimeString(); }}
+                                                    @break
+                                                @case('hourly')
+                                                    {{ \Carbon\Carbon::parse($server->last_billed)->addHour()->toDayDateTimeString(); }}
+                                                    @break
+                                                @case('quarterly')
+                                                    {{ \Carbon\Carbon::parse($server->last_billed)->addMonths(3)->toDayDateTimeString(); }}
+                                                    @break
+                                                @case('half-annually')
+                                                    {{ \Carbon\Carbon::parse($server->last_billed)->addMonths(6)->toDayDateTimeString(); }}
+                                                    @break
+                                                @case('annually')
+                                                    {{ \Carbon\Carbon::parse($server->last_billed)->addYear()->toDayDateTimeString(); }}
+                                                    @break
+                                                @default
+                                                    {{ __('Unknown') }}
+                                            @endswitch
+                                        @endif
+                                        </span>
+                                    </div>
+                                </div>
+
+                                <div class="row mb-2">
+                                    <div class="col-4">
+                                        {{ __('Price') }}:
+                                        <span class="text-muted">
+                                            ({{ CREDITS_DISPLAY_NAME }})
+                                        </span>
+                                    </div>
+                                    <div class="col-8 text-center">
+                                        <div class="text-muted">
+                                        @if($server->product->billing_period == 'monthly')
+                                            {{ __('per Month') }}
+                                        @elseif($server->product->billing_period == 'half-annually')
+                                            {{ __('per 6 Months') }}
+                                        @elseif($server->product->billing_period == 'quarterly')
+                                            {{ __('per 3 Months') }}
+                                        @elseif($server->product->billing_period == 'annually')
+                                            {{ __('per Year') }}
+                                        @elseif($server->product->billing_period == 'weekly')
+                                            {{ __('per Week') }}
+                                        @elseif($server->product->billing_period == 'daily')
+                                            {{ __('per Day') }}
+                                        @elseif($server->product->billing_period == 'hourly')
+                                            {{ __('per Hour') }}
+                                        @endif
                                             </div>
-                                        </div>
+                                        <span>
+                                            {{ $server->product->price == round($server->product->price) ? round($server->product->price) : $server->product->price }}
+                                        </span>
                                     </div>
                                 </div>
                             </div>
+                        </div>
 
-                            <div class="card-footer d-flex align-items-center justify-content-between">
-                                <a href="{{ config('SETTINGS::SYSTEM:PTERODACTYL:URL') }}/server/{{ $server->identifier }}"
-                                    target="__blank"
-                                    class="btn btn-info mx-3 w-100 align-items-center justify-content-center d-flex">
-                                    <i class="fas fa-tools mr-2"></i>
-                                    <span>{{ __('Manage') }}</span>
-                                </a>
-                                <a href="{{ route('servers.show', ['server' => $server->id])}}" class="btn btn-warning mx-3 w-100 align-items-center justify-content-center d-flex">
-                                    <i class="fas fa-cog mr-2"></i>
-                                    <span>{{ __('Settings') }}</span>
-                                </a>
-                            </div>
+                        <div class="card-footer text-center">
+                            <a href="{{ config('SETTINGS::SYSTEM:PTERODACTYL:URL') }}/server/{{ $server->identifier }}"
+                                target="__blank"
+                                class="btn btn-info text-center float-left ml-2"
+                                data-toggle="tooltip" data-placement="bottom" title="{{ __('Manage Server') }}">
+                                <i class="fas fa-tools mx-2"></i>
+                            </a>
+                            @if(config("SETTINGS::SYSTEM:PTERODACTYL:ADMIN_USER_TOKEN"))
+                            <a href="{{ route('servers.show', ['server' => $server->id])}}"
+                            	class="btn btn-info text-center mr-3"
+                            	data-toggle="tooltip" data-placement="bottom" title="{{ __('Server Settings') }}">
+                                <i class="fas fa-cog mx-2"></i>
+                            </a>
+                            @endif
+                            <button onclick="handleServerCancel('{{ $server->id }}');" target="__blank"
+                                class="btn btn-warning  text-center"
+                                {{ $server->suspended || $server->cancelled ? "disabled" : "" }}
+                                data-toggle="tooltip" data-placement="bottom" title="{{ __('Cancel Server') }}">
+                                <i class="fas fa-ban mx-2"></i>
+                            </button>
+                            <button onclick="handleServerDelete('{{ $server->id }}');" target="__blank"
+                                class="btn btn-danger  text-center float-right mr-2"
+                                data-toggle="tooltip" data-placement="bottom" title="{{ __('Delete Server') }}">
+                                <i class="fas fa-trash mx-2"></i>
+                            </button>
                         </div>
-                    @endif
+                    </div>
                 @endforeach
             </div>
             <!-- END CUSTOM CONTENT -->
         </div>
     </section>
     <!-- END CONTENT -->
+
+    <script>
+        const handleServerCancel = (serverId) => {
+            // Handle server cancel with sweetalert
+            Swal.fire({
+                title: "{{ __('Cancel Server?') }}",
+                text: "{{ __('This will cancel your current server to the next billing period. It will get suspended when the current period runs out.') }}",
+                icon: 'warning',
+                confirmButtonColor: '#d9534f',
+                showCancelButton: true,
+                confirmButtonText: "{{ __('Yes, cancel it!') }}",
+                cancelButtonText: "{{ __('No, abort!') }}",
+                reverseButtons: true
+            }).then((result) => {
+                if (result.value) {
+                    // Delete server
+                    fetch("{{ route('servers.cancel', '') }}" + '/' + serverId, {
+                        method: 'PATCH',
+                        headers: {
+                            'X-CSRF-TOKEN': '{{ csrf_token() }}'
+                        }
+                    }).then(() => {
+                        window.location.reload();
+                    });
+                    return
+                }
+            })
+        }
+
+        const handleServerDelete = (serverId) => {
+            Swal.fire({
+                title: "{{ __('Delete Server?') }}",
+                html: "{{!! __('This is an irreversible action, all files of this server will be removed. <strong>No funds will get refunded</strong>. We recommend deleting the server when server is suspended.') !!}}",
+                icon: 'warning',
+                confirmButtonColor: '#d9534f',
+                showCancelButton: true,
+                confirmButtonText: "{{ __('Yes, delete it!') }}",
+                cancelButtonText: "{{ __('No, abort!') }}",
+                reverseButtons: true
+            }).then((result) => {
+                if (result.value) {
+                    // Delete server
+                    fetch("{{ route('servers.destroy', '') }}" + '/' + serverId, {
+                        method: 'DELETE',
+                        headers: {
+                            'X-CSRF-TOKEN': '{{ csrf_token() }}'
+                        }
+                    }).then(() => {
+                        window.location.reload();
+                    });
+                    return
+                }
+            });
+
+        }
+
+        document.addEventListener('DOMContentLoaded', () => {
+            $('[data-toggle="popover"]').popover();
+        });
+
+        $(function () {
+            $('[data-toggle="tooltip"]').tooltip()
+        })
+    </script>
 @endsection