full widget support
This commit is contained in:
parent
fca86ac4dc
commit
023b4884d1
File diff suppressed because one or more lines are too long
5
init.php
5
init.php
@ -112,6 +112,11 @@ $result = ORM::for_table('tbl_appconfig')->find_many();
|
|||||||
foreach ($result as $value) {
|
foreach ($result as $value) {
|
||||||
$config[$value['setting']] = $value['value'];
|
$config[$value['setting']] = $value['value'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(empty($config['dashboard_cr'])){
|
||||||
|
$config['dashboard_cr'] = "12.7,5.12";
|
||||||
|
}
|
||||||
|
|
||||||
$_c = $config;
|
$_c = $config;
|
||||||
if (empty($http_proxy) && !empty($config['http_proxy'])) {
|
if (empty($http_proxy) && !empty($config['http_proxy'])) {
|
||||||
$http_proxy = $config['http_proxy'];
|
$http_proxy = $config['http_proxy'];
|
||||||
|
@ -1,233 +1,56 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
||||||
* by https://t.me/ibnux
|
* by https://t.me/ibnux
|
||||||
**/
|
**/
|
||||||
|
|
||||||
_admin();
|
_admin();
|
||||||
$ui->assign('_title', Lang::T('Dashboard'));
|
$ui->assign('_title', Lang::T('Dashboard'));
|
||||||
$ui->assign('_admin', $admin);
|
$ui->assign('_admin', $admin);
|
||||||
|
|
||||||
if (isset($_GET['refresh'])) {
|
if (isset($_GET['refresh'])) {
|
||||||
$files = scandir($CACHE_PATH);
|
$files = scandir($CACHE_PATH);
|
||||||
foreach ($files as $file) {
|
foreach ($files as $file) {
|
||||||
$ext = pathinfo($file, PATHINFO_EXTENSION);
|
$ext = pathinfo($file, PATHINFO_EXTENSION);
|
||||||
if (is_file($CACHE_PATH . DIRECTORY_SEPARATOR . $file) && $ext == 'temp') {
|
if (is_file($CACHE_PATH . DIRECTORY_SEPARATOR . $file) && $ext == 'temp') {
|
||||||
unlink($CACHE_PATH . DIRECTORY_SEPARATOR . $file);
|
unlink($CACHE_PATH . DIRECTORY_SEPARATOR . $file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
r2(getUrl('dashboard'), 's', 'Data Refreshed');
|
r2(getUrl('dashboard'), 's', 'Data Refreshed');
|
||||||
}
|
}
|
||||||
|
|
||||||
$reset_day = $config['reset_day'];
|
|
||||||
if (empty($reset_day)) {
|
$reset_day = $config['reset_day'];
|
||||||
$reset_day = 1;
|
if (empty($reset_day)) {
|
||||||
}
|
$reset_day = 1;
|
||||||
//first day of month
|
}
|
||||||
if (date("d") >= $reset_day) {
|
//first day of month
|
||||||
$start_date = date('Y-m-' . $reset_day);
|
if (date("d") >= $reset_day) {
|
||||||
} else {
|
$start_date = date('Y-m-' . $reset_day);
|
||||||
$start_date = date('Y-m-' . $reset_day, strtotime("-1 MONTH"));
|
} else {
|
||||||
}
|
$start_date = date('Y-m-' . $reset_day, strtotime("-1 MONTH"));
|
||||||
|
}
|
||||||
$current_date = date('Y-m-d');
|
|
||||||
$month_n = date('n');
|
$current_date = date('Y-m-d');
|
||||||
|
$ui->assign('start_date', $start_date);
|
||||||
$iday = ORM::for_table('tbl_transactions')
|
$ui->assign('current_date', $current_date);
|
||||||
->where('recharged_on', $current_date)
|
|
||||||
->where_not_equal('method', 'Customer - Balance')
|
$widgets = ORM::for_table('tbl_widgets')->selects("enabled", 1)->order_by_asc("orders")->findArray();
|
||||||
->where_not_equal('method', 'Recharge Balance - Administrator')
|
$count = count($widgets);
|
||||||
->sum('price');
|
for ($i = 0; $i < $count; $i++) {
|
||||||
|
try{
|
||||||
if ($iday == '') {
|
if(file_exists($WIDGET_PATH . DIRECTORY_SEPARATOR . $widgets[$i]['widget'].".php")){
|
||||||
$iday = '0.00';
|
require_once $WIDGET_PATH . DIRECTORY_SEPARATOR . $widgets[$i]['widget'].".php";
|
||||||
}
|
$widgets[$i]['content'] = (new $widgets[$i]['widget'])->getWidget($widgets[$i]);
|
||||||
$ui->assign('iday', $iday);
|
}else{
|
||||||
|
$widgets[$i]['content'] = "Widget not found";
|
||||||
$imonth = ORM::for_table('tbl_transactions')
|
}
|
||||||
->where_not_equal('method', 'Customer - Balance')
|
} catch (Throwable $e) {
|
||||||
->where_not_equal('method', 'Recharge Balance - Administrator')
|
$widgets[$i]['content'] = $e->getMessage();
|
||||||
->where_gte('recharged_on', $start_date)
|
}
|
||||||
->where_lte('recharged_on', $current_date)->sum('price');
|
}
|
||||||
if ($imonth == '') {
|
|
||||||
$imonth = '0.00';
|
$ui->assign('widgets', $widgets);
|
||||||
}
|
run_hook('view_dashboard'); #HOOK
|
||||||
$ui->assign('imonth', $imonth);
|
$ui->display('admin/dashboard.tpl');
|
||||||
|
|
||||||
if ($config['enable_balance'] == 'yes'){
|
|
||||||
$cb = ORM::for_table('tbl_customers')->whereGte('balance', 0)->sum('balance');
|
|
||||||
$ui->assign('cb', $cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
$u_act = ORM::for_table('tbl_user_recharges')->where('status', 'on')->count();
|
|
||||||
if (empty($u_act)) {
|
|
||||||
$u_act = '0';
|
|
||||||
}
|
|
||||||
$ui->assign('u_act', $u_act);
|
|
||||||
|
|
||||||
$u_all = ORM::for_table('tbl_user_recharges')->count();
|
|
||||||
if (empty($u_all)) {
|
|
||||||
$u_all = '0';
|
|
||||||
}
|
|
||||||
$ui->assign('u_all', $u_all);
|
|
||||||
|
|
||||||
|
|
||||||
$c_all = ORM::for_table('tbl_customers')->count();
|
|
||||||
if (empty($c_all)) {
|
|
||||||
$c_all = '0';
|
|
||||||
}
|
|
||||||
$ui->assign('c_all', $c_all);
|
|
||||||
|
|
||||||
if ($config['hide_uet'] != 'yes') {
|
|
||||||
//user expire
|
|
||||||
$query = ORM::for_table('tbl_user_recharges')
|
|
||||||
->where_lte('expiration', $current_date)
|
|
||||||
->order_by_desc('expiration');
|
|
||||||
$expire = Paginator::findMany($query);
|
|
||||||
|
|
||||||
// Get the total count of expired records for pagination
|
|
||||||
$totalCount = ORM::for_table('tbl_user_recharges')
|
|
||||||
->where_lte('expiration', $current_date)
|
|
||||||
->count();
|
|
||||||
|
|
||||||
// Pass the total count and current page to the paginator
|
|
||||||
$paginator['total_count'] = $totalCount;
|
|
||||||
|
|
||||||
// Assign the pagination HTML to the template variable
|
|
||||||
$ui->assign('expire', $expire);
|
|
||||||
}
|
|
||||||
|
|
||||||
//activity log
|
|
||||||
$dlog = ORM::for_table('tbl_logs')->limit(5)->order_by_desc('id')->find_many();
|
|
||||||
$ui->assign('dlog', $dlog);
|
|
||||||
$log = ORM::for_table('tbl_logs')->count();
|
|
||||||
$ui->assign('log', $log);
|
|
||||||
|
|
||||||
|
|
||||||
if ($config['hide_vs'] != 'yes') {
|
|
||||||
$cacheStocksfile = $CACHE_PATH . File::pathFixer('/VoucherStocks.temp');
|
|
||||||
$cachePlanfile = $CACHE_PATH . File::pathFixer('/VoucherPlans.temp');
|
|
||||||
//Cache for 5 minutes
|
|
||||||
if (file_exists($cacheStocksfile) && time() - filemtime($cacheStocksfile) < 600) {
|
|
||||||
$stocks = json_decode(file_get_contents($cacheStocksfile), true);
|
|
||||||
$plans = json_decode(file_get_contents($cachePlanfile), true);
|
|
||||||
} else {
|
|
||||||
// Count stock
|
|
||||||
$tmp = $v = ORM::for_table('tbl_plans')->select('id')->select('name_plan')->find_many();
|
|
||||||
$plans = array();
|
|
||||||
$stocks = array("used" => 0, "unused" => 0);
|
|
||||||
$n = 0;
|
|
||||||
foreach ($tmp as $plan) {
|
|
||||||
$unused = ORM::for_table('tbl_voucher')
|
|
||||||
->where('id_plan', $plan['id'])
|
|
||||||
->where('status', 0)->count();
|
|
||||||
$used = ORM::for_table('tbl_voucher')
|
|
||||||
->where('id_plan', $plan['id'])
|
|
||||||
->where('status', 1)->count();
|
|
||||||
if ($unused > 0 || $used > 0) {
|
|
||||||
$plans[$n]['name_plan'] = $plan['name_plan'];
|
|
||||||
$plans[$n]['unused'] = $unused;
|
|
||||||
$plans[$n]['used'] = $used;
|
|
||||||
$stocks["unused"] += $unused;
|
|
||||||
$stocks["used"] += $used;
|
|
||||||
$n++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_put_contents($cacheStocksfile, json_encode($stocks));
|
|
||||||
file_put_contents($cachePlanfile, json_encode($plans));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$cacheMRfile = File::pathFixer('/monthlyRegistered.temp');
|
|
||||||
//Cache for 1 hour
|
|
||||||
if (file_exists($cacheMRfile) && time() - filemtime($cacheMRfile) < 3600) {
|
|
||||||
$monthlyRegistered = json_decode(file_get_contents($cacheMRfile), true);
|
|
||||||
} else {
|
|
||||||
//Monthly Registered Customers
|
|
||||||
$result = ORM::for_table('tbl_customers')
|
|
||||||
->select_expr('MONTH(created_at)', 'month')
|
|
||||||
->select_expr('COUNT(*)', 'count')
|
|
||||||
->where_raw('YEAR(created_at) = YEAR(NOW())')
|
|
||||||
->group_by_expr('MONTH(created_at)')
|
|
||||||
->find_many();
|
|
||||||
|
|
||||||
$monthlyRegistered = [];
|
|
||||||
foreach ($result as $row) {
|
|
||||||
$monthlyRegistered[] = [
|
|
||||||
'date' => $row->month,
|
|
||||||
'count' => $row->count
|
|
||||||
];
|
|
||||||
}
|
|
||||||
file_put_contents($cacheMRfile, json_encode($monthlyRegistered));
|
|
||||||
}
|
|
||||||
|
|
||||||
$cacheMSfile = $CACHE_PATH . File::pathFixer('/monthlySales.temp');
|
|
||||||
//Cache for 12 hours
|
|
||||||
if (file_exists($cacheMSfile) && time() - filemtime($cacheMSfile) < 43200) {
|
|
||||||
$monthlySales = json_decode(file_get_contents($cacheMSfile), true);
|
|
||||||
} else {
|
|
||||||
// Query to retrieve monthly data
|
|
||||||
$results = ORM::for_table('tbl_transactions')
|
|
||||||
->select_expr('MONTH(recharged_on)', 'month')
|
|
||||||
->select_expr('SUM(price)', 'total')
|
|
||||||
->where_raw("YEAR(recharged_on) = YEAR(CURRENT_DATE())") // Filter by the current year
|
|
||||||
->where_not_equal('method', 'Customer - Balance')
|
|
||||||
->where_not_equal('method', 'Recharge Balance - Administrator')
|
|
||||||
->group_by_expr('MONTH(recharged_on)')
|
|
||||||
->find_many();
|
|
||||||
|
|
||||||
// Create an array to hold the monthly sales data
|
|
||||||
$monthlySales = array();
|
|
||||||
|
|
||||||
// Iterate over the results and populate the array
|
|
||||||
foreach ($results as $result) {
|
|
||||||
$month = $result->month;
|
|
||||||
$totalSales = $result->total;
|
|
||||||
|
|
||||||
$monthlySales[$month] = array(
|
|
||||||
'month' => $month,
|
|
||||||
'totalSales' => $totalSales
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill in missing months with zero sales
|
|
||||||
for ($month = 1; $month <= 12; $month++) {
|
|
||||||
if (!isset($monthlySales[$month])) {
|
|
||||||
$monthlySales[$month] = array(
|
|
||||||
'month' => $month,
|
|
||||||
'totalSales' => 0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort the array by month
|
|
||||||
ksort($monthlySales);
|
|
||||||
|
|
||||||
// Reindex the array
|
|
||||||
$monthlySales = array_values($monthlySales);
|
|
||||||
file_put_contents($cacheMSfile, json_encode($monthlySales));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($config['router_check']) {
|
|
||||||
$routeroffs = ORM::for_table('tbl_routers')->selects(['id', 'name', 'last_seen'])->where('status', 'Offline')->where('enabled', '1')->order_by_desc('name')->find_array();
|
|
||||||
$ui->assign('routeroffs', $routeroffs);
|
|
||||||
}
|
|
||||||
|
|
||||||
$timestampFile = "$UPLOAD_PATH/cron_last_run.txt";
|
|
||||||
if (file_exists($timestampFile)) {
|
|
||||||
$lastRunTime = file_get_contents($timestampFile);
|
|
||||||
$ui->assign('run_date', date('Y-m-d h:i:s A', $lastRunTime));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assign the monthly sales data to Smarty
|
|
||||||
$ui->assign('start_date', $start_date);
|
|
||||||
$ui->assign('current_date', $current_date);
|
|
||||||
$ui->assign('monthlySales', $monthlySales);
|
|
||||||
$ui->assign('xfooter', '');
|
|
||||||
$ui->assign('monthlyRegistered', $monthlyRegistered);
|
|
||||||
$ui->assign('stocks', $stocks);
|
|
||||||
$ui->assign('plans', $plans);
|
|
||||||
|
|
||||||
run_hook('view_dashboard'); #HOOK
|
|
||||||
$ui->display('admin/dashboard.tpl');
|
|
@ -1,56 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PHP Mikrotik Billing (https://github.com/hotspotbilling/phpnuxbill/)
|
|
||||||
* by https://t.me/ibnux
|
|
||||||
**/
|
|
||||||
|
|
||||||
_admin();
|
|
||||||
$ui->assign('_title', Lang::T('Dashboard'));
|
|
||||||
$ui->assign('_admin', $admin);
|
|
||||||
|
|
||||||
if (isset($_GET['refresh'])) {
|
|
||||||
$files = scandir($CACHE_PATH);
|
|
||||||
foreach ($files as $file) {
|
|
||||||
$ext = pathinfo($file, PATHINFO_EXTENSION);
|
|
||||||
if (is_file($CACHE_PATH . DIRECTORY_SEPARATOR . $file) && $ext == 'temp') {
|
|
||||||
unlink($CACHE_PATH . DIRECTORY_SEPARATOR . $file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
r2(getUrl('dashboard'), 's', 'Data Refreshed');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$reset_day = $config['reset_day'];
|
|
||||||
if (empty($reset_day)) {
|
|
||||||
$reset_day = 1;
|
|
||||||
}
|
|
||||||
//first day of month
|
|
||||||
if (date("d") >= $reset_day) {
|
|
||||||
$start_date = date('Y-m-' . $reset_day);
|
|
||||||
} else {
|
|
||||||
$start_date = date('Y-m-' . $reset_day, strtotime("-1 MONTH"));
|
|
||||||
}
|
|
||||||
|
|
||||||
$current_date = date('Y-m-d');
|
|
||||||
$ui->assign('start_date', $start_date);
|
|
||||||
$ui->assign('current_date', $current_date);
|
|
||||||
|
|
||||||
$widgets = ORM::for_table('tbl_widgets')->selects("enabled", 1)->order_by_asc("orders")->findArray();
|
|
||||||
$count = count($widgets);
|
|
||||||
for ($i = 0; $i < $count; $i++) {
|
|
||||||
try{
|
|
||||||
if(file_exists($WIDGET_PATH . DIRECTORY_SEPARATOR . $widgets[$i]['widget'].".php")){
|
|
||||||
require_once $WIDGET_PATH . DIRECTORY_SEPARATOR . $widgets[$i]['widget'].".php";
|
|
||||||
$widgets[$i]['content'] = (new $widgets[$i]['widget'])->getWidget($widgets[$i]);
|
|
||||||
}else{
|
|
||||||
$widgets[$i]['content'] = "Widget not found";
|
|
||||||
}
|
|
||||||
} catch (Throwable $e) {
|
|
||||||
$widgets[$i]['content'] = $e->getMessage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$ui->assign('widgets', $widgets);
|
|
||||||
run_hook('view_dashboard'); #HOOK
|
|
||||||
$ui->display('admin/dashboard_widget.tpl');
|
|
@ -11,6 +11,13 @@ $ui->assign('_system_menu', 'settings');
|
|||||||
$action = alphanumeric($routes['1']);
|
$action = alphanumeric($routes['1']);
|
||||||
$ui->assign('_admin', $admin);
|
$ui->assign('_admin', $admin);
|
||||||
|
|
||||||
|
$max = ORM::for_table('tbl_widgets')->max('position');
|
||||||
|
$max2 = substr_count($config['dashboard_cr'], '.')+substr_count($config['dashboard_cr'], ',')+1;
|
||||||
|
if($max2>$max){
|
||||||
|
$max = $max2;
|
||||||
|
}
|
||||||
|
$ui->assign('max', $max);
|
||||||
|
|
||||||
if ($action == 'add') {
|
if ($action == 'add') {
|
||||||
$pos = alphanumeric($routes['2']);
|
$pos = alphanumeric($routes['2']);
|
||||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||||
@ -104,9 +111,20 @@ if ($action == 'add') {
|
|||||||
}
|
}
|
||||||
r2(getUrl('widgets'), 's', 'Widget order Saved Successfully');
|
r2(getUrl('widgets'), 's', 'Widget order Saved Successfully');
|
||||||
} else {
|
} else {
|
||||||
|
if(_post("save") == 'struct'){
|
||||||
|
$d = ORM::for_table('tbl_appconfig')->where('setting', 'dashboard_cr')->find_one();
|
||||||
|
if ($d) {
|
||||||
|
$d->value = _post('dashboard_cr');
|
||||||
|
$d->save();
|
||||||
|
} else {
|
||||||
|
$d = ORM::for_table('tbl_appconfig')->create();
|
||||||
|
$d->setting = 'dashboard_cr';
|
||||||
|
$d->value = _post('dashboard_cr');
|
||||||
|
$d->save();
|
||||||
|
}
|
||||||
|
_alert("Dashboard Structure Saved Successfully", "success", getUrl('widgets'));
|
||||||
|
}
|
||||||
$widgets = ORM::for_table('tbl_widgets')->selects("position", 1)->order_by_asc("orders")->find_many();
|
$widgets = ORM::for_table('tbl_widgets')->selects("position", 1)->order_by_asc("orders")->find_many();
|
||||||
$max = ORM::for_table('tbl_widgets')->max('position');
|
|
||||||
$ui->assign('widgets', $widgets);
|
$ui->assign('widgets', $widgets);
|
||||||
$ui->assign('max', $max);
|
|
||||||
$ui->display('admin/settings/widgets.tpl');
|
$ui->display('admin/settings/widgets.tpl');
|
||||||
}
|
}
|
||||||
|
@ -1049,5 +1049,8 @@
|
|||||||
"Sending___": "Sending...",
|
"Sending___": "Sending...",
|
||||||
"Message_sent_successfully_": "Message sent successfully.",
|
"Message_sent_successfully_": "Message sent successfully.",
|
||||||
"Error_sending_message__": "Error sending message: ",
|
"Error_sending_message__": "Error sending message: ",
|
||||||
"Failed_to_send_the_message__Please_try_again_": "Failed to send the message. Please try again."
|
"Failed_to_send_the_message__Please_try_again_": "Failed to send the message. Please try again.",
|
||||||
|
"Dashboard_Structure": "Dashboard Structure",
|
||||||
|
"Read_documentation": "Read documentation",
|
||||||
|
"Structure": "Structure"
|
||||||
}
|
}
|
@ -1,420 +1,37 @@
|
|||||||
{include file="sections/header.tpl"}
|
{include file="sections/header.tpl"}
|
||||||
|
|
||||||
<div class="row">
|
{function showWidget pos=0}
|
||||||
{if in_array($_admin['user_type'],['SuperAdmin','Admin', 'Report'])}
|
{foreach $widgets as $w}
|
||||||
<div class="col-lg-3 col-xs-6">
|
{if $w['position'] == $pos}
|
||||||
<div class="small-box bg-aqua">
|
{$w['content']}
|
||||||
<div class="inner">
|
{/if}
|
||||||
<h4 class="text-bold" style="font-size: large;"><sup>{$_c['currency_code']}</sup>
|
{/foreach}
|
||||||
{number_format($iday,0,$_c['dec_point'],$_c['thousands_sep'])}</h4>
|
{/function}
|
||||||
</div>
|
|
||||||
<div class="icon">
|
|
||||||
<i class="ion ion-clock"></i>
|
{assign rows explode(".", $_c['dashboard_cr'])}
|
||||||
</div>
|
{assign pos 1}
|
||||||
<a href="{Text::url('reports/by-date')}" class="small-box-footer">{Lang::T('Income Today')}</a>
|
{foreach $rows as $cols}
|
||||||
|
{if $cols == 12}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
{showWidget widgets=$widgets pos=$pos}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-3 col-xs-6">
|
{assign pos value=$pos+1}
|
||||||
<div class="small-box bg-green">
|
{else}
|
||||||
<div class="inner">
|
{assign colss explode(",", $cols)}
|
||||||
<h4 class="text-bold" style="font-size: large;"><sup>{$_c['currency_code']}</sup>
|
<div class="row">
|
||||||
{number_format($imonth,0,$_c['dec_point'],$_c['thousands_sep'])}</h4>
|
{foreach $colss as $c}
|
||||||
|
<div class="col-md-{$c}">
|
||||||
|
{showWidget widgets=$widgets pos=$pos}
|
||||||
</div>
|
</div>
|
||||||
<div class="icon">
|
{assign pos value=$pos+1}
|
||||||
<i class="ion ion-android-calendar"></i>
|
{/foreach}
|
||||||
</div>
|
|
||||||
<a href="{Text::url('reports/by-period')}" class="small-box-footer">{Lang::T('Income This Month')}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="col-lg-3 col-xs-6">
|
{/foreach}
|
||||||
<div class="small-box bg-yellow">
|
|
||||||
<div class="inner">
|
|
||||||
<h4 class="text-bold" style="font-size: large;">{$u_act}/{$u_all-$u_act}</h4>
|
|
||||||
</div>
|
|
||||||
<div class="icon">
|
|
||||||
<i class="ion ion-person"></i>
|
|
||||||
</div>
|
|
||||||
<a href="{Text::url('plan/list')}" class="small-box-footer">{Lang::T('Active')}/{Lang::T('Expired')}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-lg-3 col-xs-6">
|
|
||||||
<div class="small-box bg-red">
|
|
||||||
<div class="inner">
|
|
||||||
<h4 class="text-bold" style="font-size: large;">{$c_all}</h4>
|
|
||||||
</div>
|
|
||||||
<div class="icon">
|
|
||||||
<i class="ion ion-android-people"></i>
|
|
||||||
</div>
|
|
||||||
<a href="{Text::url('customers/list')}" class="small-box-footer">{Lang::T('Customers')}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<ol class="breadcrumb">
|
|
||||||
<li>{Lang::dateFormat($start_date)}</li>
|
|
||||||
<li>{Lang::dateFormat($current_date)}</li>
|
|
||||||
{if $_c['enable_balance'] == 'yes' && in_array($_admin['user_type'],['SuperAdmin','Admin', 'Report'])}
|
|
||||||
<li onclick="window.location.href = '{Text::url('customers&search=&order=balance&filter=Active&orderby=desc')}'" style="cursor: pointer;">
|
|
||||||
{Lang::T('Customer Balance')} <sup>{$_c['currency_code']}</sup>
|
|
||||||
<b>{number_format($cb,0,$_c['dec_point'],$_c['thousands_sep'])}</b>
|
|
||||||
</li>
|
|
||||||
{/if}
|
|
||||||
</ol>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-7">
|
|
||||||
|
|
||||||
<!-- solid sales graph -->
|
|
||||||
{if $_c['hide_mrc'] != 'yes'}
|
|
||||||
<div class="box box-solid ">
|
|
||||||
<div class="box-header">
|
|
||||||
<i class="fa fa-th"></i>
|
|
||||||
|
|
||||||
<h3 class="box-title">{Lang::T('Monthly Registered Customers')}</h3>
|
|
||||||
|
|
||||||
<div class="box-tools pull-right">
|
|
||||||
<button type="button" class="btn bg-teal btn-sm" data-widget="collapse"><i class="fa fa-minus"></i>
|
|
||||||
</button>
|
|
||||||
<a href="{Text::url('dashboard&refresh')}" class="btn bg-teal btn-sm"><i class="fa fa-refresh"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="box-body border-radius-none">
|
|
||||||
<canvas class="chart" id="chart" style="height: 250px;"></canvas>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<!-- solid sales graph -->
|
|
||||||
{if $_c['hide_tms'] != 'yes'}
|
|
||||||
<div class="box box-solid ">
|
|
||||||
<div class="box-header">
|
|
||||||
<i class="fa fa-inbox"></i>
|
|
||||||
|
|
||||||
<h3 class="box-title">{Lang::T('Total Monthly Sales')}</h3>
|
|
||||||
|
|
||||||
<div class="box-tools pull-right">
|
|
||||||
<button type="button" class="btn bg-teal btn-sm" data-widget="collapse"><i class="fa fa-minus"></i>
|
|
||||||
</button>
|
|
||||||
<a href="{Text::url('dashboard&refresh')}" class="btn bg-teal btn-sm"><i class="fa fa-refresh"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="box-body border-radius-none">
|
|
||||||
<canvas class="chart" id="salesChart" style="height: 250px;"></canvas>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
{if $_c['disable_voucher'] != 'yes' && $stocks['unused']>0 || $stocks['used']>0}
|
|
||||||
{if $_c['hide_vs'] != 'yes'}
|
|
||||||
<div class="panel panel-primary mb20 panel-hovered project-stats table-responsive">
|
|
||||||
<div class="panel-heading">Vouchers Stock</div>
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table class="table table-condensed">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>{Lang::T('Package Name')}</th>
|
|
||||||
<th>unused</th>
|
|
||||||
<th>used</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{foreach $plans as $stok}
|
|
||||||
<tr>
|
|
||||||
<td>{$stok['name_plan']}</td>
|
|
||||||
<td>{$stok['unused']}</td>
|
|
||||||
<td>{$stok['used']}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
{/foreach}
|
|
||||||
<tr>
|
|
||||||
<td>Total</td>
|
|
||||||
<td>{$stocks['unused']}</td>
|
|
||||||
<td>{$stocks['used']}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
{/if}
|
|
||||||
{if $_c['hide_uet'] != 'yes'}
|
|
||||||
<div class="panel panel-warning mb20 panel-hovered project-stats table-responsive">
|
|
||||||
<div class="panel-heading">{Lang::T('User Expired, Today')}</div>
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table class="table table-condensed">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>{Lang::T('Username')}</th>
|
|
||||||
<th>{Lang::T('Created / Expired')}</th>
|
|
||||||
<th>{Lang::T('Internet Package')}</th>
|
|
||||||
<th>{Lang::T('Location')}</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{foreach $expire as $expired}
|
|
||||||
{assign var="rem_exp" value="{$expired['expiration']} {$expired['time']}"}
|
|
||||||
{assign var="rem_started" value="{$expired['recharged_on']} {$expired['recharged_time']}"}
|
|
||||||
<tr>
|
|
||||||
<td><a href="{Text::url('customers/viewu/',$expired['username'])}">{$expired['username']}</a></td>
|
|
||||||
<td><small data-toggle="tooltip" data-placement="top"
|
|
||||||
title="{Lang::dateAndTimeFormat($expired['recharged_on'],$expired['recharged_time'])}">{Lang::timeElapsed($rem_started)}</small>
|
|
||||||
/
|
|
||||||
<span data-toggle="tooltip" data-placement="top"
|
|
||||||
title="{Lang::dateAndTimeFormat($expired['expiration'],$expired['time'])}">{Lang::timeElapsed($rem_exp)}</span>
|
|
||||||
</td>
|
|
||||||
<td>{$expired['namebp']}</td>
|
|
||||||
<td>{$expired['routers']}</td>
|
|
||||||
</tr>
|
|
||||||
{/foreach}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{include file="pagination.tpl"}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="col-md-5">
|
|
||||||
{if $_c['router_check'] && count($routeroffs)> 0}
|
|
||||||
<div class="panel panel-danger">
|
|
||||||
<div class="panel-heading text-bold">{Lang::T('Routers Offline')}</div>
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table class="table table-condensed">
|
|
||||||
<tbody>
|
|
||||||
{foreach $routeroffs as $ros}
|
|
||||||
<tr>
|
|
||||||
<td><a href="{Text::url('routers/edit/',$ros['id'])}" class="text-bold text-red">{$ros['name']}</a></td>
|
|
||||||
<td data-toggle="tooltip" data-placement="top" class="text-red"
|
|
||||||
title="{Lang::dateTimeFormat($ros['last_seen'])}">{Lang::timeElapsed($ros['last_seen'])}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{/foreach}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
{if $run_date}
|
|
||||||
{assign var="current_time" value=$smarty.now}
|
|
||||||
{assign var="run_time" value=strtotime($run_date)}
|
|
||||||
{if $current_time - $run_time > 3600}
|
|
||||||
<div class="panel panel-cron-warning panel-hovered mb20 activities">
|
|
||||||
<div class="panel-heading"><i class="fa fa-clock-o"></i> {Lang::T('Cron has not run for over 1 hour. Please
|
|
||||||
check your setup.')}</div>
|
|
||||||
</div>
|
|
||||||
{else}
|
|
||||||
<div class="panel panel-cron-success panel-hovered mb20 activities">
|
|
||||||
<div class="panel-heading">{Lang::T('Cron Job last ran on')}: {$run_date}</div>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
{else}
|
|
||||||
<div class="panel panel-cron-danger panel-hovered mb20 activities">
|
|
||||||
<div class="panel-heading"><i class="fa fa-warning"></i> {Lang::T('Cron appear not been setup, please check
|
|
||||||
your cron setup.')}</div>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
{if $_c['hide_pg'] != 'yes'}
|
|
||||||
<div class="panel panel-success panel-hovered mb20 activities">
|
|
||||||
<div class="panel-heading">{Lang::T('Payment Gateway')}: {str_replace(',',', ',$_c['payment_gateway'])}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
{if $_c['hide_aui'] != 'yes'}
|
|
||||||
<div class="panel panel-info panel-hovered mb20 activities">
|
|
||||||
<div class="panel-heading">{Lang::T('All Users Insights')}</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<canvas id="userRechargesChart"></canvas>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
{if $_c['hide_al'] != 'yes'}
|
|
||||||
<div class="panel panel-info panel-hovered mb20 activities">
|
|
||||||
<div class="panel-heading"><a href="{Text::url('logs')}">{Lang::T('Activity Log')}</a></div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<ul class="list-unstyled">
|
|
||||||
{foreach $dlog as $dlogs}
|
|
||||||
<li class="primary">
|
|
||||||
<span class="point"></span>
|
|
||||||
<span class="time small text-muted">{Lang::timeElapsed($dlogs['date'],true)}</span>
|
|
||||||
<p>{$dlogs['description']}</p>
|
|
||||||
</li>
|
|
||||||
{/foreach}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.5.1/dist/chart.min.js"></script>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
{if $_c['hide_mrc'] != 'yes'}
|
|
||||||
{literal}
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
|
||||||
var counts = JSON.parse('{/literal}{$monthlyRegistered|json_encode}{literal}');
|
|
||||||
|
|
||||||
var monthNames = [
|
|
||||||
'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
|
|
||||||
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
|
|
||||||
];
|
|
||||||
|
|
||||||
var labels = [];
|
|
||||||
var data = [];
|
|
||||||
|
|
||||||
for (var i = 1; i <= 12; i++) {
|
|
||||||
var month = counts.find(count => count.date === i);
|
|
||||||
labels.push(month ? monthNames[i - 1] : monthNames[i - 1].substring(0, 3));
|
|
||||||
data.push(month ? month.count : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
var ctx = document.getElementById('chart').getContext('2d');
|
|
||||||
var chart = new Chart(ctx, {
|
|
||||||
type: 'bar',
|
|
||||||
data: {
|
|
||||||
labels: labels,
|
|
||||||
datasets: [{
|
|
||||||
label: 'Registered Members',
|
|
||||||
data: data,
|
|
||||||
backgroundColor: 'rgba(0, 0, 255, 0.5)',
|
|
||||||
borderColor: 'rgba(0, 0, 255, 0.7)',
|
|
||||||
borderWidth: 1
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
responsive: true,
|
|
||||||
scales: {
|
|
||||||
x: {
|
|
||||||
grid: {
|
|
||||||
display: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
y: {
|
|
||||||
beginAtZero: true,
|
|
||||||
grid: {
|
|
||||||
color: 'rgba(0, 0, 0, 0.1)'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
{/literal}
|
|
||||||
{/if}
|
|
||||||
{if $_c['hide_tmc'] != 'yes'}
|
|
||||||
{literal}
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
|
||||||
var monthlySales = JSON.parse('{/literal}{$monthlySales|json_encode}{literal}');
|
|
||||||
|
|
||||||
var monthNames = [
|
|
||||||
'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
|
|
||||||
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
|
|
||||||
];
|
|
||||||
|
|
||||||
var labels = [];
|
|
||||||
var data = [];
|
|
||||||
|
|
||||||
for (var i = 1; i <= 12; i++) {
|
|
||||||
var month = findMonthData(monthlySales, i);
|
|
||||||
labels.push(month ? monthNames[i - 1] : monthNames[i - 1].substring(0, 3));
|
|
||||||
data.push(month ? month.totalSales : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
var ctx = document.getElementById('salesChart').getContext('2d');
|
|
||||||
var chart = new Chart(ctx, {
|
|
||||||
type: 'bar',
|
|
||||||
data: {
|
|
||||||
labels: labels,
|
|
||||||
datasets: [{
|
|
||||||
label: 'Monthly Sales',
|
|
||||||
data: data,
|
|
||||||
backgroundColor: 'rgba(2, 10, 242)', // Customize the background color
|
|
||||||
borderColor: 'rgba(255, 99, 132, 1)', // Customize the border color
|
|
||||||
borderWidth: 1
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
responsive: true,
|
|
||||||
scales: {
|
|
||||||
x: {
|
|
||||||
grid: {
|
|
||||||
display: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
y: {
|
|
||||||
beginAtZero: true,
|
|
||||||
grid: {
|
|
||||||
color: 'rgba(0, 0, 0, 0.1)'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function findMonthData(monthlySales, month) {
|
|
||||||
for (var i = 0; i < monthlySales.length; i++) {
|
|
||||||
if (monthlySales[i].month === month) {
|
|
||||||
return monthlySales[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
{/literal}
|
|
||||||
{/if}
|
|
||||||
{if $_c['hide_aui'] != 'yes'}
|
|
||||||
{literal}
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
|
||||||
// Get the data from PHP and assign it to JavaScript variables
|
|
||||||
var u_act = '{/literal}{$u_act}{literal}';
|
|
||||||
var c_all = '{/literal}{$c_all}{literal}';
|
|
||||||
var u_all = '{/literal}{$u_all}{literal}';
|
|
||||||
//lets calculate the inactive users as reported
|
|
||||||
var expired = u_all - u_act;
|
|
||||||
var inactive = c_all - u_all;
|
|
||||||
if (inactive < 0) {
|
|
||||||
inactive = 0;
|
|
||||||
}
|
|
||||||
// Create the chart data
|
|
||||||
var data = {
|
|
||||||
labels: ['Active Users', 'Expired Users', 'Inactive Users'],
|
|
||||||
datasets: [{
|
|
||||||
label: 'User Recharges',
|
|
||||||
data: [parseInt(u_act), parseInt(expired), parseInt(inactive)],
|
|
||||||
backgroundColor: ['rgba(4, 191, 13)', 'rgba(191, 35, 4)', 'rgba(0, 0, 255, 0.5'],
|
|
||||||
borderColor: ['rgba(0, 255, 0, 1)', 'rgba(255, 99, 132, 1)', 'rgba(0, 0, 255, 0.7'],
|
|
||||||
borderWidth: 1
|
|
||||||
}]
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create chart options
|
|
||||||
var options = {
|
|
||||||
responsive: true,
|
|
||||||
aspectRatio: 1,
|
|
||||||
plugins: {
|
|
||||||
legend: {
|
|
||||||
position: 'bottom',
|
|
||||||
labels: {
|
|
||||||
boxWidth: 15
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get the canvas element and create the chart
|
|
||||||
var ctx = document.getElementById('userRechargesChart').getContext('2d');
|
|
||||||
var chart = new Chart(ctx, {
|
|
||||||
type: 'pie',
|
|
||||||
data: data,
|
|
||||||
options: options
|
|
||||||
});
|
|
||||||
});
|
|
||||||
{/literal}
|
|
||||||
{/if}
|
|
||||||
</script>
|
|
||||||
{if $_c['new_version_notify'] != 'disable'}
|
{if $_c['new_version_notify'] != 'disable'}
|
||||||
<script>
|
<script>
|
||||||
window.addEventListener('DOMContentLoaded', function() {
|
window.addEventListener('DOMContentLoaded', function() {
|
||||||
@ -456,4 +73,4 @@
|
|||||||
</script>
|
</script>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{include file="sections/footer.tpl"}
|
{include file="sections/footer.tpl"}
|
@ -1,94 +0,0 @@
|
|||||||
{include file="sections/header.tpl"}
|
|
||||||
|
|
||||||
{function showWidget pos=0}
|
|
||||||
{foreach $widgets as $w}
|
|
||||||
{if $w['position'] == $pos}
|
|
||||||
{$w['content']}
|
|
||||||
{/if}
|
|
||||||
{/foreach}
|
|
||||||
{/function}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{if $_c['dashboard'] == '1.55.1'}
|
|
||||||
{showWidget widgets=$widgets pos=1}
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
{showWidget widgets=$widgets pos=2}
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
{showWidget widgets=$widgets pos=3}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{showWidget widgets=$widgets pos=4}
|
|
||||||
{elseif $_c['dashboard'] == '1.57.1'}
|
|
||||||
{showWidget widgets=$widgets pos=1}
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-5">
|
|
||||||
{showWidget widgets=$widgets pos=2}
|
|
||||||
</div>
|
|
||||||
<div class="col-md-7">
|
|
||||||
{showWidget widgets=$widgets pos=3}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{showWidget widgets=$widgets pos=4}
|
|
||||||
{elseif $_c['dashboard'] == '1.1.1.1'}
|
|
||||||
{showWidget widgets=$widgets pos=1}
|
|
||||||
{showWidget widgets=$widgets pos=2}
|
|
||||||
{showWidget widgets=$widgets pos=3}
|
|
||||||
{showWidget widgets=$widgets pos=4}
|
|
||||||
{else}
|
|
||||||
{showWidget widgets=$widgets pos=1}
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-7">
|
|
||||||
{showWidget widgets=$widgets pos=2}
|
|
||||||
</div>
|
|
||||||
<div class="col-md-5">
|
|
||||||
{showWidget widgets=$widgets pos=3}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{showWidget widgets=$widgets pos=4}
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{if $_c['new_version_notify'] != 'disable'}
|
|
||||||
<script>
|
|
||||||
window.addEventListener('DOMContentLoaded', function() {
|
|
||||||
$.getJSON("./version.json?" + Math.random(), function(data) {
|
|
||||||
var localVersion = data.version;
|
|
||||||
$('#version').html('Version: ' + localVersion);
|
|
||||||
$.getJSON(
|
|
||||||
"https://raw.githubusercontent.com/hotspotbilling/phpnuxbill/master/version.json?" +
|
|
||||||
Math
|
|
||||||
.random(),
|
|
||||||
function(data) {
|
|
||||||
var latestVersion = data.version;
|
|
||||||
if (localVersion !== latestVersion) {
|
|
||||||
$('#version').html('Latest Version: ' + latestVersion);
|
|
||||||
if (getCookie(latestVersion) != 'done') {
|
|
||||||
Swal.fire({
|
|
||||||
icon: 'info',
|
|
||||||
title: "New Version Available\nVersion: " + latestVersion,
|
|
||||||
toast: true,
|
|
||||||
position: 'bottom-right',
|
|
||||||
showConfirmButton: true,
|
|
||||||
showCloseButton: true,
|
|
||||||
timer: 30000,
|
|
||||||
confirmButtonText: '<a href="{Text::url('community')}#latestVersion" style="color: white;">Update Now</a>',
|
|
||||||
timerProgressBar: true,
|
|
||||||
didOpen: (toast) => {
|
|
||||||
toast.addEventListener('mouseenter', Swal.stopTimer)
|
|
||||||
toast.addEventListener('mouseleave', Swal
|
|
||||||
.resumeTimer)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
setCookie(latestVersion, 'done', 7);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{include file="sections/footer.tpl"}
|
|
@ -1,6 +1,6 @@
|
|||||||
{include file="sections/header.tpl"}
|
{include file="sections/header.tpl"}
|
||||||
|
|
||||||
<form class="form-horizontal" method="post" role="form" action="{Text::url('')}settings/notifications-post">
|
<form class="form-horizontal" method="post" role="form" action="{Text::url('settings/notifications-post')}">
|
||||||
<input type="hidden" name="csrf_token" value="{$csrf_token}">
|
<input type="hidden" name="csrf_token" value="{$csrf_token}">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12 col-md-12">
|
<div class="col-sm-12 col-md-12">
|
||||||
@ -26,7 +26,7 @@
|
|||||||
<b>[[package]]</b> - {Lang::T('will be replaced with Package name')}.<br>
|
<b>[[package]]</b> - {Lang::T('will be replaced with Package name')}.<br>
|
||||||
<b>[[price]]</b> - {Lang::T('will be replaced with Package price')}.<br>
|
<b>[[price]]</b> - {Lang::T('will be replaced with Package price')}.<br>
|
||||||
<b>[[bills]]</b> - {Lang::T('additional bills for customers')}.<br>
|
<b>[[bills]]</b> - {Lang::T('additional bills for customers')}.<br>
|
||||||
<b>[[payment_link]]</b> - <a href="{Text::url('docs')}/docs/#Reminder%20with%20payment%20link"
|
<b>[[payment_link]]</b> - <a href="{$app_url}/docs/#Reminder%20with%20payment%20link"
|
||||||
target="_blank">read documentation</a>.
|
target="_blank">read documentation</a>.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@ -45,7 +45,7 @@
|
|||||||
<b>[[price]]</b> - {Lang::T('will be replaced with Package price')}.<br>
|
<b>[[price]]</b> - {Lang::T('will be replaced with Package price')}.<br>
|
||||||
<b>[[expired_date]]</b> - {Lang::T('will be replaced with Expiration date')}.<br>
|
<b>[[expired_date]]</b> - {Lang::T('will be replaced with Expiration date')}.<br>
|
||||||
<b>[[bills]]</b> - {Lang::T('additional bills for customers')}.<br>
|
<b>[[bills]]</b> - {Lang::T('additional bills for customers')}.<br>
|
||||||
<b>[[payment_link]]</b> - <a href="{Text::url('docs')}/docs/#Reminder%20with%20payment%20link"
|
<b>[[payment_link]]</b> - <a href="{$app_url}/docs/#Reminder%20with%20payment%20link"
|
||||||
target="_blank">read documentation</a>.
|
target="_blank">read documentation</a>.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@ -64,7 +64,7 @@
|
|||||||
<b>[[price]]</b> - {Lang::T('will be replaced with Package price')}.<br>
|
<b>[[price]]</b> - {Lang::T('will be replaced with Package price')}.<br>
|
||||||
<b>[[expired_date]]</b> - {Lang::T('will be replaced with Expiration date')}.<br>
|
<b>[[expired_date]]</b> - {Lang::T('will be replaced with Expiration date')}.<br>
|
||||||
<b>[[bills]]</b> - {Lang::T('additional bills for customers')}.<br>
|
<b>[[bills]]</b> - {Lang::T('additional bills for customers')}.<br>
|
||||||
<b>[[payment_link]]</b> - <a href="{Text::url('docs')}/docs/#Reminder%20with%20payment%20link"
|
<b>[[payment_link]]</b> - <a href="{$app_url}/docs/#Reminder%20with%20payment%20link"
|
||||||
target="_blank">read documentation</a>.
|
target="_blank">read documentation</a>.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@ -83,7 +83,7 @@
|
|||||||
<b>[[price]]</b> - {Lang::T('will be replaced with Package price')}.<br>
|
<b>[[price]]</b> - {Lang::T('will be replaced with Package price')}.<br>
|
||||||
<b>[[expired_date]]</b> - {Lang::T('will be replaced with Expiration date')}.<br>
|
<b>[[expired_date]]</b> - {Lang::T('will be replaced with Expiration date')}.<br>
|
||||||
<b>[[bills]]</b> - {Lang::T('additional bills for customers')}.<br>
|
<b>[[bills]]</b> - {Lang::T('additional bills for customers')}.<br>
|
||||||
<b>[[payment_link]]</b> - <a href="{Text::url('docs')}/docs/#Reminder%20with%20payment%20link"
|
<b>[[payment_link]]</b> - <a href="{$app_url}/docs/#Reminder%20with%20payment%20link"
|
||||||
target="_blank">read documentation</a>.
|
target="_blank">read documentation</a>.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
{include file="sections/header.tpl"}
|
{include file="sections/header.tpl"}
|
||||||
|
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
{function showWidget pos=0}
|
{function showWidget pos=0}
|
||||||
<form method="post" action="{Text::url('widgets/pos/')}">
|
<form method="post" action="{Text::url('widgets/pos/')}">
|
||||||
<div class="panel panel-info">
|
<div class="panel panel-info">
|
||||||
@ -49,11 +52,64 @@
|
|||||||
{/function}
|
{/function}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{for $pos=1 to $max}
|
<div class="col-md-3">
|
||||||
<div class="col-md-6 col-lg-4">
|
<div class="panel panel-info">
|
||||||
{showWidget widgets=$widgets pos=$pos}
|
<div class="panel-heading">Dashboard Structure</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
{assign rows explode(".", $_c['dashboard_cr'])}
|
||||||
|
{assign pos 1}
|
||||||
|
{foreach $rows as $cols}
|
||||||
|
{if $cols == 12}
|
||||||
|
<div class="row row-no-gutters">
|
||||||
|
<div class="col-xs-12" style="border: 1px;">
|
||||||
|
<a href="{Text::url('widgets/add/', $pos)}" class="btn btn-default btn-block">{$pos}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{assign pos value=$pos+1}
|
||||||
|
{else}
|
||||||
|
{assign colss explode(",", $cols)}
|
||||||
|
<div class="row row-no-gutters">
|
||||||
|
{foreach $colss as $c}
|
||||||
|
<div class="col-xs-{$c}">
|
||||||
|
<a href="{Text::url('widgets/add/', $pos)}" class="btn btn-default btn-block">{$pos}</a>
|
||||||
|
</div>
|
||||||
|
{assign pos value=$pos+1}
|
||||||
|
{/foreach}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{/foreach}
|
||||||
|
</div>
|
||||||
|
<div class="panel-footer">
|
||||||
|
<form method="post" action="{Text::url('widgets')}">
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-addon"><a href="{$app_url}/docs/#Dashboard%20Structure"
|
||||||
|
target="_blank">{Lang::T("Structure")}</a></span>
|
||||||
|
<input type="text" name="dashboard_cr" value="{$_c['dashboard_cr']}" class="form-control"
|
||||||
|
placeholder="Dashboard">
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary btn-block" name="save" value="struct">{Lang::T("Save")}</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/for}
|
</div>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
{for $pos=1 to $max}
|
||||||
|
{if $pos%2 != 0}
|
||||||
|
{showWidget widgets=$widgets pos=$pos}
|
||||||
|
{/if}
|
||||||
|
{/for}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
{for $pos=1 to $max}
|
||||||
|
{if $pos%2 == 0}
|
||||||
|
{showWidget widgets=$widgets pos=$pos}
|
||||||
|
{/if}
|
||||||
|
{/for}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{include file="sections/footer.tpl"}
|
{include file="sections/footer.tpl"}
|
@ -40,7 +40,7 @@
|
|||||||
<label class="col-md-3 control-label">{Lang::T('Position')}</label>
|
<label class="col-md-3 control-label">{Lang::T('Position')}</label>
|
||||||
<div class="col-md-5">
|
<div class="col-md-5">
|
||||||
<select name="position" id="position" class="form-control">
|
<select name="position" id="position" class="form-control">
|
||||||
{for $pos=1 to 12}
|
{for $pos=1 to $max}
|
||||||
<option value="{$pos}" {if $widget['position'] eq $pos}selected="selected" {/if}>
|
<option value="{$pos}" {if $widget['position'] eq $pos}selected="selected" {/if}>
|
||||||
Area {$pos}
|
Area {$pos}
|
||||||
</option>
|
</option>
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"version": "2025.2.12.1"
|
"version": "2025.2.18"
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user