diff --git a/init.php b/init.php index d330cdeb..ad9f5958 100644 --- a/init.php +++ b/init.php @@ -56,6 +56,7 @@ $UPLOAD_PATH = $root_path . File::pathFixer('system/uploads'); $CACHE_PATH = $root_path . File::pathFixer('system/cache'); $PAGES_PATH = $root_path . File::pathFixer('pages'); $PLUGIN_PATH = $root_path . File::pathFixer('system/plugin'); +$WIDGET_PATH = $root_path . File::pathFixer('system/widgets'); $PAYMENTGATEWAY_PATH = $root_path . File::pathFixer('system/paymentgateway'); $UI_PATH = 'ui'; diff --git a/system/autoload/Paginator.php b/system/autoload/Paginator.php index 4b6dbc43..13675e26 100644 --- a/system/autoload/Paginator.php +++ b/system/autoload/Paginator.php @@ -19,6 +19,7 @@ class Paginator $url .= '&' . http_build_query($search); } $url .= $append_url.'&p='; + $url = Text::fixUrl($url); $totalReq = $query->count(); $lastpage = ceil($totalReq / $per_page); $lpm1 = $lastpage - 1; diff --git a/system/autoload/Text.php b/system/autoload/Text.php index f60b9621..1f58366a 100644 --- a/system/autoload/Text.php +++ b/system/autoload/Text.php @@ -132,6 +132,14 @@ class Text } } + public static function fixUrl($url){ + //if url dont have ? then add it with replace first & to ? + if(strpos($url, '?') === false && strpos($url, '&')!== false){ + return substr($url, 0, strpos($url, '&')). '?'. substr($url, strpos($url, '&')+1); + } + return $url; + } + // this will return & or ? public static function isQA(){ global $config; diff --git a/system/autoload/Widget.php b/system/autoload/Widget.php new file mode 100644 index 00000000..0a368c25 --- /dev/null +++ b/system/autoload/Widget.php @@ -0,0 +1,50 @@ +'; + foreach($rows as $row){ + + } + $result .= ''; + } + + public static function columns($cols, $result){ + $c = count($cols); + switch($c){ + case 1: + $result .= '
'; + break; + case 2: + $result .= '
'; + break; + case 3: + $result .= '
'; + break; + case 4: + $result .= '
'; + break; + case 5: + $result .= '
'; + break; + default: + $result .= '
'; + break; + } + + foreach($cols as $col){ + } + $result .= '
'; + } +} \ No newline at end of file diff --git a/system/controllers/dashboard_widget.php b/system/controllers/dashboard_widget.php new file mode 100644 index 00000000..a4937662 --- /dev/null +++ b/system/controllers/dashboard_widget.php @@ -0,0 +1,185 @@ +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'); + +$widgets = ORM::for_table('tbl_widgets')->selects("enabled", 1)->order_by_asc("orders")->findArray(); +$count = count($widgets); +for ($i = 0; $i < $count; $i++) { + try{ + require_once $WIDGET_PATH . DIRECTORY_SEPARATOR . $widgets[$i]['widget'].".php"; + $widgets[$i]['content'] = (new $widgets[$i]['widget'])->getWidget($widgets[$i]);; + } catch (Throwable $e) { + $widgets[$i]['content'] = $e->getMessage(); + } +} + +$ui->assign('widgets', $widgets); +run_hook('view_dashboard'); #HOOK +$ui->display('admin/dashboard_widget.tpl'); +die(); + +//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'); diff --git a/system/controllers/widgets.php b/system/controllers/widgets.php new file mode 100644 index 00000000..e74a8c33 --- /dev/null +++ b/system/controllers/widgets.php @@ -0,0 +1,102 @@ +assign('_title', Lang::T('Widgets')); +$ui->assign('_system_menu', 'settings'); + +$action = alphanumeric($routes['1']); +$ui->assign('_admin', $admin); + +if ($action == 'add') { + $pos = alphanumeric($routes['2']); + if ($_SERVER['REQUEST_METHOD'] == 'POST') { + $orders = alphanumeric($_POST['orders']); + $position = alphanumeric($_POST['position']); + $enabled = alphanumeric($_POST['enabled']); + $title = _post('title'); + $widget = _post('widget'); + $content = _post('content'); + $d = ORM::for_table('tbl_widgets')->create(); + $d->orders = $orders; + $d->position = $position; + $d->enabled = $enabled; + $d->title = $title; + $d->widget = $widget; + $d->content = $content; + $d->save(); + if ($d->id() > 0) { + r2(getUrl('widgets'), 's', 'Widget Added Successfully'); + } + } + $files = scandir($WIDGET_PATH); + $widgets = []; + foreach ($files as $file) { + if (strpos($file, '.php') !== false) { + $name = ucwords(str_replace('.php', '', str_replace('_', ' ', $file))); + $widgets[str_replace('.php', '', $file)] = $name; + } + } + $widget['position'] = $pos; + $ui->assign('do', 'add'); + $ui->assign('widgets', $widgets); + $ui->assign('widget', $widget); + $ui->display('admin/settings/widgets_add_edit.tpl'); +} else if ($action == 'edit') { + // if request method post then save data + if ($_SERVER['REQUEST_METHOD'] == 'POST') { + $id = alphanumeric($_POST['id']); + $orders = alphanumeric($_POST['orders']); + $position = alphanumeric($_POST['position']); + $enabled = alphanumeric($_POST['enabled']); + $title = _post('title'); + $widget = _post('widget'); + $content = _post('content'); + + $d = ORM::for_table('tbl_widgets')->find_one($id); + $d->orders = $orders; + $d->position = $position; + $d->enabled = $enabled; + $d->title = $title; + $d->widget = $widget; + $d->content = $content; + $d->save(); + r2(getUrl('widgets'), 's', 'Widget Saved Successfully'); + } + $id = alphanumeric($routes['2']); + $widget = ORM::for_table('tbl_widgets')->find_one($id); + $files = scandir($WIDGET_PATH); + $widgets = []; + foreach ($files as $file) { + if (strpos($file, '.php') !== false) { + $name = ucwords(str_replace('.php', '', str_replace('_', ' ', $file))); + $widgets[str_replace('.php', '', $file)] = $name; + } + } + $ui->assign('do', 'edit'); + $ui->assign('widgets', $widgets); + $ui->assign('widget', $widget); + $ui->display('admin/settings/widgets_add_edit.tpl'); +} else if ($action == 'delete') { + $id = alphanumeric($routes['2']); + $d = ORM::for_table('tbl_widgets')->find_one($id); + if ($d) { + $d->delete(); + r2(getUrl('widgets'), 's', 'Widget Deleted Successfully'); + } + r2(getUrl('widgets'), 'e', 'Widget Not Found'); +} else if (!empty($action) && file_exists("system/widget/$action.php") && !empty($routes['2'])) { + require_once "system/widget/$action.php"; + try { + (new $action)->run_command($routes['2']); + } catch (Throwable $e) { + //nothing to do + } +} else { + $widgets = ORM::for_table('tbl_widgets')->selects("position", 1)->order_by_asc("orders")->find_many(); + $ui->assign('widgets', $widgets); + $ui->display('admin/settings/widgets.tpl'); +} diff --git a/system/lan/english.json b/system/lan/english.json index 261d8081..2d153dc5 100644 --- a/system/lan/english.json +++ b/system/lan/english.json @@ -1027,5 +1027,12 @@ "Back_to_Dashboard": "Back to Dashboard", "Continue_the_VPN_creation_process_": "Continue the VPN creation process?", "VPN": "VPN", - "Go_Back": "Go Back" + "Go_Back": "Go Back", + "Widgets": "Widgets", + "Order": "Order", + "Position": "Position", + "Widget": "Widget", + "Contents": "Contents", + "Please_enter_a_search_term_": "Please enter a search term.", + "Customers_Expired__Today": "Customers Expired, Today" } \ No newline at end of file diff --git a/system/widgets/customer_expired.php b/system/widgets/customer_expired.php new file mode 100644 index 00000000..ede3e4f8 --- /dev/null +++ b/system/widgets/customer_expired.php @@ -0,0 +1,30 @@ +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); + return $ui->fetch('widget/customer_expired.tpl'); + } +} diff --git a/system/widgets/html_php.php b/system/widgets/html_php.php new file mode 100644 index 00000000..dcbb9040 --- /dev/null +++ b/system/widgets/html_php.php @@ -0,0 +1,22 @@ +assign('card_header', $data['title']); + ob_start(); + try{ + eval('?>'. $data['content']); + }catch(Exception $e){ + echo $e->getMessage(); + echo "
"; + echo $e->getTraceAsString(); + } + $content = ob_get_clean(); + $ui->assign('card_body', $content); + return $ui->fetch('widget/card_html.tpl'); + } +} \ No newline at end of file diff --git a/system/widgets/template.md b/system/widgets/template.md new file mode 100644 index 00000000..3d3fe053 --- /dev/null +++ b/system/widgets/template.md @@ -0,0 +1,18 @@ +fetch('widget/template'); + } +} +``` diff --git a/system/widgets/top_widget.php b/system/widgets/top_widget.php new file mode 100644 index 00000000..3c6909a9 --- /dev/null +++ b/system/widgets/top_widget.php @@ -0,0 +1,56 @@ +where('recharged_on', $current_date) + ->where_not_equal('method', 'Customer - Balance') + ->where_not_equal('method', 'Recharge Balance - Administrator') + ->sum('price'); + + if ($iday == '') { + $iday = '0.00'; + } + $ui->assign('iday', $iday); + + $imonth = ORM::for_table('tbl_transactions') + ->where_not_equal('method', 'Customer - Balance') + ->where_not_equal('method', 'Recharge Balance - Administrator') + ->where_gte('recharged_on', $start_date) + ->where_lte('recharged_on', $current_date)->sum('price'); + if ($imonth == '') { + $imonth = '0.00'; + } + $ui->assign('imonth', $imonth); + + 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); + return $ui->fetch('widget/top_widget.tpl'); + } +} diff --git a/ui/ui/admin/dashboard_widget.tpl b/ui/ui/admin/dashboard_widget.tpl new file mode 100644 index 00000000..af3fba80 --- /dev/null +++ b/ui/ui/admin/dashboard_widget.tpl @@ -0,0 +1,66 @@ +{include file="sections/header.tpl"} + +{function showWidget pos=0} + {foreach $widgets as $w} + {if $w['position'] == $pos} + {$w['content']} + {/if} + {/foreach} +{/function} + + + +{showWidget widgets=$widgets pos=1} +
+
+ {showWidget widgets=$widgets pos=2} +
+
+ {showWidget widgets=$widgets pos=3} +
+
+{showWidget widgets=$widgets pos=4} + + +{if $_c['new_version_notify'] != 'disable'} + +{/if} + +{include file="sections/footer.tpl"} \ No newline at end of file diff --git a/ui/ui/admin/header.tpl b/ui/ui/admin/header.tpl index 631d601f..f0c1fd3d 100644 --- a/ui/ui/admin/header.tpl +++ b/ui/ui/admin/header.tpl @@ -20,8 +20,10 @@ - + + + diff --git a/ui/ui/admin/settings/widgets.tpl b/ui/ui/admin/settings/widgets.tpl new file mode 100644 index 00000000..b605e80a --- /dev/null +++ b/ui/ui/admin/settings/widgets.tpl @@ -0,0 +1,73 @@ +{include file="sections/header.tpl"} + + +{function showWidget pos=0} +
+
+
Area {$pos}
+
+ {foreach $widgets as $w} + {if $w['position'] == $pos} +
+
{$w['title']}
+
{ucwords(str_replace('.php', '', str_replace('_', ' ', $w['widget'])))}
+ + + + + +
+
+ orders + +
+ +
+
+ edit + +
+
+
+ {/if} + {/foreach} +
+ +
+
+{/function} + + +
+
+ {showWidget widgets=$widgets pos=1} +
+
+
+
+ {showWidget widgets=$widgets pos=2} +
+
+ {showWidget widgets=$widgets pos=3} +
+
+ +
+
+ {showWidget widgets=$widgets pos=4} +
+
+ + + +{include file="sections/footer.tpl"} \ No newline at end of file diff --git a/ui/ui/admin/settings/widgets_add_edit.tpl b/ui/ui/admin/settings/widgets_add_edit.tpl new file mode 100644 index 00000000..79c96b3c --- /dev/null +++ b/ui/ui/admin/settings/widgets_add_edit.tpl @@ -0,0 +1,92 @@ +{include file="sections/header.tpl"} + +
+
+
+
+
{if $do == 'add'}{Lang::T('Add')}{else}{Lang::T('Edit')}{/if} Widget
+
+ +
+ +
+ +
+   +
+
+ +
+ +
+   +
+
+ +
+ +
+

 

+
+
+ +
+ +
+

 

+
+
+ +
+ +
+

 

+
+
+ +
+ +

Not All Widget need contents, HTML widget need content, it can be text + or PHP Code, be careful

+
+
+
+ +
+ {if $do == 'edit'} + {Lang::T('Delete')} + {/if} +
+
+
+ +{include file="sections/footer.tpl"} \ No newline at end of file diff --git a/ui/ui/widget/activity_log.tpl b/ui/ui/widget/activity_log.tpl new file mode 100644 index 00000000..28dfc88a --- /dev/null +++ b/ui/ui/widget/activity_log.tpl @@ -0,0 +1,14 @@ +
+ +
+
    + {foreach $dlog as $dlogs} +
  • + + {Lang::timeElapsed($dlogs['date'],true)} +

    {$dlogs['description']}

    +
  • + {/foreach} +
+
+
\ No newline at end of file diff --git a/ui/ui/widget/card_html.tpl b/ui/ui/widget/card_html.tpl new file mode 100644 index 00000000..39d924fb --- /dev/null +++ b/ui/ui/widget/card_html.tpl @@ -0,0 +1,5 @@ +
+
{$card_header}
+
{$card_body} +
+
\ No newline at end of file diff --git a/ui/ui/widget/cron_monitor.tpl b/ui/ui/widget/cron_monitor.tpl new file mode 100644 index 00000000..72258fac --- /dev/null +++ b/ui/ui/widget/cron_monitor.tpl @@ -0,0 +1,19 @@ +{if $run_date} + {assign var="current_time" value=$smarty.now} + {assign var="run_time" value=strtotime($run_date)} + {if $current_time - $run_time > 3600} +
+
  {Lang::T('Cron has not run for over 1 hour. Please + check your setup.')}
+
+ {else} +
+
{Lang::T('Cron Job last ran on')}: {$run_date}
+
+ {/if} +{else} +
+
  {Lang::T('Cron appear not been setup, please check + your cron setup.')}
+
+{/if} \ No newline at end of file diff --git a/ui/ui/widget/customer_expired.tpl b/ui/ui/widget/customer_expired.tpl new file mode 100644 index 00000000..dda37187 --- /dev/null +++ b/ui/ui/widget/customer_expired.tpl @@ -0,0 +1,33 @@ +
+
{Lang::T('Customers Expired, Today')}
+
+ + + + + + + + + + + {foreach $expire as $expired} + {assign var="rem_exp" value="{$expired['expiration']} {$expired['time']}"} + {assign var="rem_started" value="{$expired['recharged_on']} {$expired['recharged_time']}"} + + + + + + + {/foreach} + +
{Lang::T('Username')}{Lang::T('Created / Expired')}{Lang::T('Internet Package')}{Lang::T('Location')}
{$expired['username']}{Lang::timeElapsed($rem_started)} + / + {Lang::timeElapsed($rem_exp)} + {$expired['namebp']}{$expired['routers']}
+
+   {include file="pagination.tpl"} +
\ No newline at end of file diff --git a/ui/ui/widget/default_info_row.tpl b/ui/ui/widget/default_info_row.tpl new file mode 100644 index 00000000..7b83a9e6 --- /dev/null +++ b/ui/ui/widget/default_info_row.tpl @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/ui/ui/widget/graph_customers_insight.tpl b/ui/ui/widget/graph_customers_insight.tpl new file mode 100644 index 00000000..e94d8aea --- /dev/null +++ b/ui/ui/widget/graph_customers_insight.tpl @@ -0,0 +1,59 @@ +
+
{Lang::T('All Users Insights')}
+
+ +
+
+ + + \ No newline at end of file diff --git a/ui/ui/widget/graph_monthly_registered_customers.tpl b/ui/ui/widget/graph_monthly_registered_customers.tpl new file mode 100644 index 00000000..0f4a682e --- /dev/null +++ b/ui/ui/widget/graph_monthly_registered_customers.tpl @@ -0,0 +1,73 @@ +
+
+ + +

{Lang::T('Monthly Registered Customers')}

+ +
+ + + +
+
+
+ +
+
+ + + \ No newline at end of file diff --git a/ui/ui/widget/graph_monthly_sales.tpl b/ui/ui/widget/graph_monthly_sales.tpl new file mode 100644 index 00000000..ec0b7684 --- /dev/null +++ b/ui/ui/widget/graph_monthly_sales.tpl @@ -0,0 +1,81 @@ +
+
+ + +

{Lang::T('Total Monthly Sales')}

+ +
+ + + +
+
+
+ +
+
+ + \ No newline at end of file diff --git a/ui/ui/widget/info_payment_gateway.tpl b/ui/ui/widget/info_payment_gateway.tpl new file mode 100644 index 00000000..38f5b540 --- /dev/null +++ b/ui/ui/widget/info_payment_gateway.tpl @@ -0,0 +1,4 @@ +
+
{Lang::T('Payment Gateway')}: {str_replace(',',', ',$_c['payment_gateway'])} +
+
\ No newline at end of file diff --git a/ui/ui/widget/mikrotik_offline.tpl b/ui/ui/widget/mikrotik_offline.tpl new file mode 100644 index 00000000..31e4dd0b --- /dev/null +++ b/ui/ui/widget/mikrotik_offline.tpl @@ -0,0 +1,19 @@ +{if $_c['router_check'] && count($routeroffs)> 0} +
+
{Lang::T('Routers Offline')}
+
+ + + {foreach $routeroffs as $ros} + + + + + {/foreach} + +
{$ros['name']}{Lang::timeElapsed($ros['last_seen'])} +
+
+
+{/if} \ No newline at end of file diff --git a/ui/ui/widget/top_widget.tpl b/ui/ui/widget/top_widget.tpl new file mode 100644 index 00000000..d769b289 --- /dev/null +++ b/ui/ui/widget/top_widget.tpl @@ -0,0 +1,50 @@ +
+ {if in_array($_admin['user_type'],['SuperAdmin','Admin', 'Report'])} +
+
+
+

{$_c['currency_code']} + {number_format($iday,0,$_c['dec_point'],$_c['thousands_sep'])}

+
+
+ +
+ {Lang::T('Income Today')} +
+
+
+
+
+

{$_c['currency_code']} + {number_format($imonth,0,$_c['dec_point'],$_c['thousands_sep'])}

+
+
+ +
+ {Lang::T('Income This Month')} +
+
+ {/if} +
+
+
+

{$u_act}/{$u_all-$u_act}

+
+
+ +
+ {Lang::T('Active')}/{Lang::T('Expired')} +
+
+
+
+
+

{$c_all}

+
+
+ +
+ {Lang::T('Customers')} +
+
+
\ No newline at end of file diff --git a/ui/ui/widget/voucher_stocks.tpl b/ui/ui/widget/voucher_stocks.tpl new file mode 100644 index 00000000..c3b0a7f1 --- /dev/null +++ b/ui/ui/widget/voucher_stocks.tpl @@ -0,0 +1,30 @@ +{if $_c['disable_voucher'] != 'yes' && $stocks['unused']>0 || $stocks['used']>0} +
+
Vouchers Stock
+
+ + + + + + + + + + {foreach $plans as $stok} + + + + + + + {/foreach} + + + + + +
{Lang::T('Package Name')}unusedused
{$stok['name_plan']}{$stok['unused']}{$stok['used']}
Total{$stocks['unused']}{$stocks['used']}
+
+
+{/if} \ No newline at end of file