<?php
require_once('config.php');
$uid=$_SESSION['user'];
$userFile=ABSPATH.'data/users/'.preg_replace('/[^a-zA-Z0-9_-]/','',$uid).'.meta';
$uData=file_exists($userFile)?loadMeta($userFile):[];
$uPrefs=$uData['prefs']??[];
$PER_PAGE_DESKTOP=(int)($uPrefs['PER_PAGE_DESKTOP']??$PER_PAGE_DESKTOP);
$PER_PAGE_MOBILE=(int)($uPrefs['PER_PAGE_MOBILE']??$PER_PAGE_MOBILE);
$contactSortMode=$uPrefs['contactSortMode']??$contactSortMode;
$contactNameSortMode=$uPrefs['contactNameSortMode']??$contactNameSortMode;
if(!isset($_SESSION['user'])||!has_permission('inboxmenu')){header("Location:login.php");exit;}
$currentUser=$_SESSION['user'];
$isAdmin=is_admin();
$contactDir=ABSPATH.'data/contacts/';
if(!is_dir($contactDir)){@mkdir($contactDir,0755,true);}
$publicFile=$contactDir.'public.json';
$privateFile=$contactDir.'user_'.$currentUser.'.json';
function saveContacts($file,$data){return saveMeta($file,array_values($data));}
function loadContacts($file){if(!file_exists($file)) return [];$data=loadMeta($file);return is_array($data)?$data:[];}
function initContactFile($file){if(!file_exists($file)){saveContacts($file,[]);@chmod($file,0644);}}
initContactFile($publicFile);
initContactFile($privateFile);
$cSortMode=$contactSortMode??"public";
$cNameSortMode=$contactNameSortMode??"off";
$action=$_POST['cmd']??'';
if(in_array($action,['add','edit','delete'])){
if(!isset($_POST['csrf'])||$_POST['csrf']!==$_SESSION['csrf']){die("Security Error: Invalid Request Token");}
$type=$_POST['type']??'users';
if($type==='public'&&!$isAdmin){die("Admin required");}
$targetFile=($type==='public')?$publicFile:$privateFile;
$contacts=loadContacts($targetFile);
if($action==='delete'){
$contacts=array_filter($contacts,fn($c)=>$c['id']!=$_POST['id']);
saveContacts($targetFile,$contacts);
}else{
$name=trim($_POST['name']??'');
$fax=trim($_POST['fax']??'');
$memo=trim($_POST['memo']??'');
$id=$_POST['id']??'';
$newType=$_POST['type']??'users';
if($name!==''&&$fax!==''){
if($action==='add'){
$contacts=loadContacts($newType==='public'?$publicFile:$privateFile);
$contacts[]=[
'id'=>time().rand(10,99),
'name'=>$name,
'fax'=>$fax,
'memo'=>$memo,
'date'=>date('Y/m/d H:i')
];
saveContacts($newType==='public'?$publicFile:$privateFile,$contacts);
}else{
$pubContacts=loadContacts($publicFile);
$usrContacts=loadContacts($privateFile);
$pubContacts=array_filter($pubContacts,fn($c)=>$c['id']!=$id);
$usrContacts=array_filter($usrContacts,fn($c)=>$c['id']!=$id);
$newData=[
'id'=>$id,
'name'=>$name,
'fax'=>$fax,
'memo'=>$memo,
'date'=>date('Y/m/d H:i')
];
if($newType==='public'&&$isAdmin){$pubContacts[]=$newData;}else{$usrContacts[]=$newData;}
saveContacts($publicFile,$pubContacts);
saveContacts($privateFile,$usrContacts);
}}}
header("Location:fax_contacts.php?view=".urlencode($_GET['view']??'all'));exit;
}
$viewMode=$_GET['view']??'all';
$search=isset($_GET['q'])?trim($_GET['q']):'';
$searchMemo=isset($_GET['sm'])&&$_GET['sm']==='1';
$publicFiltered=[];
$usersFiltered=[];
$filterFunc=function($c)use($search,$searchMemo){
if($search==='')return true;
$found=stripos($c['name'],$search)!==false||stripos($c['fax'],$search)!==false;
if(!$found&&$searchMemo&&!empty($c['memo'])){$found=stripos($c['memo'],$search)!==false;}
return $found;
};
if($viewMode==='all'||$viewMode==='public'){
$temp=loadContacts($publicFile);
foreach($temp as &$p){$p['origin']='public';}
$publicFiltered=array_filter($temp,$filterFunc);
}
if($viewMode==='all'||$viewMode==='users'){
$temp=loadContacts($privateFile);
foreach($temp as &$u){$u['origin']='users';}
$usersFiltered=array_filter($temp,$filterFunc);
}
$sortDir=($cNameSortMode==='on')?-1:1;
$cmpFunc=function($a,$b)use($sortDir){
$valA=trim((string)$a['name']);
$valB=trim((string)$b['name']);
if($valA===$valB)return 0;
$isNumA=is_numeric($valA);
$isNumB=is_numeric($valB);
if($isNumA&&$isNumB)return($valA<$valB?-1:1)*$sortDir;
if($isNumA)return-1*$sortDir;
if($isNumB)return 1*$sortDir;
return $sortDir*strnatcasecmp($valA,$valB);
};
if($cSortMode==='public'&&$viewMode==='all'){
usort($publicFiltered,$cmpFunc);
usort($usersFiltered,$cmpFunc);
$displayList=array_merge($publicFiltered,$usersFiltered);
}else{
$displayList=array_merge($publicFiltered,$usersFiltered);
usort($displayList,$cmpFunc);
}
$isMobile=preg_match('/Mobile|Android|iPhone|iPad/i',$_SERVER['HTTP_USER_AGENT']);
$perPage=$isMobile?$PER_PAGE_MOBILE:$PER_PAGE_DESKTOP;
$page=max(1,(int)($_GET['page']??1));
$totalItems=count($displayList);
$totalPages=max(1,ceil($totalItems/$perPage));
$page=min($page,$totalPages);
$slice=array_slice($displayList,($page-1)*$perPage,$perPage);
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<meta name="format-detection" content="telephone=no">
<title><?=ns(APP_NAME)?> - <?php _nsl('Contacts');?></title>
<link rel="stylesheet" href="include/css/style.css">
<?php include('include/web/header.php');?>
<script>
window.FAX_LANG={
cancel:"<?=ns(__('Cancel'))?>",
delete:"<?=ns(__('Delete'))?>",
ok:"<?=ns(__('Ok'))?>",
searchFax:"<?=ns(__('Search Fax'))?>",
search:"<?=ns(__('Search'))?>",
contactMemo:"<?=ns(__('Contact Memo'))?>",
keyword:"<?=ns(__('Enter keyword'))?>",
withMemo:"<?=ns(__('Include memo content'))?>",
save:"<?=ns(__('Save'))?>",
memoPlaceholder:"<?=ns(__('Enter memo (optional)'))?>",
faxNumber:"<?=ns(__('Fax Number'))?>",
name:"<?=ns(__('Name'))?>",
addContact:"<?=ns(__('Add Contact'))?>",
editContact:"<?=ns(__('Edit Contact'))?>",
all:"<?=ns(__('All'))?>",
public:"<?=ns(__('Public'))?>",
user:"<?=ns(__('User'))?>",
users:"<?=ns(__('Users'))?>",
section:"<?=ns(__('Section'))?>",
contacts:"<?=ns(__('Contacts'))?>",
deleteConfirmMsg:"<?=ns(__('The selected contact will be deleted. This action cannot be undone. Are you sure you want to proceed?'))?>",
deleteContact:"<?=ns(__('DELETE CONTACTS'))?>",
alert:"<?=ns(__('Alert'))?>",
pushTitle:"<?=ns(__('Push Notification'))?>",
pushDesc:"<?=ns(__('You can register or test push notifications'))?>",
pushRegister:"<?=ns(__('Subscribe'))?>",
pushTest:"<?=ns(__('Test'))?>",
pushNotSupported:"<?=ns(__('Push is not supported in this browser'))?>",
pushNeedPermission:"<?=ns(__('Notification permission is required'))?>",
pushAlready:"<?=ns(__('Already subscribed'))?>",
pushSuccess:"<?=ns(__('Push subscription completed'))?>",
pushTestSuccess:"<?=ns(__('Test notification sent'))?>",
pushTestFail:"<?=ns(__('Test failed'))?>"
};
window.FAX_ENV={search:"<?=ns($search)?>",withMemo:<?=($searchMemo?1:0)?>,};
window.PUSH_CONFIG={publicKey:"<?=PUSH_PUBLIC_KEY?>"};
window.csrf="<?=ns($_SESSION['csrf'])?>";
const IS_ADMIN=<?php echo $isAdmin?'true':'false';?>;
const VIEW_MODE="<?=ns($viewMode)?>";
function openContactModal(mode,data=null){if(typeof window.openContactModal==='function'){window.openContactModal(mode,data,IS_ADMIN);}}
function openCategoryDialog(){window.openContactCategoryDialog(VIEW_MODE);}
</script>
<script src="include/js/base.js" defer></script>
<script src="include/js/modal.js" defer></script>
</head>
<body>
<div id="menuToggle">≡ <?php _nsl('Menu');?></div>
<div id="container">
<?php include('menu.php');?>
<div id="main">
<h2><?php _nsl('Contacts');?></h2>
<div class="table-wrapper">
<table>
<thead>
<tr>
<th class="faxlist-top" colspan="3">
<div class="faxlist-header">
<div class="faxlist-path">
<strong>
<?php
if($viewMode=='all')_nsl('All');
elseif($viewMode=='public')_nsl('Public');
else _nsl('Users');
?>
</strong>
</div>
<div class="faxlist-actions">
<button class="add-btn" onclick="openContactModal('add')"><?php _nsl('Add');?></button>
<button class="faxlist-btn" onclick="openSearchDialog()"><?php _nsl('Search');?></button>
<button class="faxlist-btn" onclick="openCategoryDialog()"><?php _nsl('Section');?></button>
</div></div>
</th>
</tr>
</thead>
<tbody>
<?php
if(empty($slice)){
echo"<tr><td colspan='3' class='web-msg'>".ns($search!==''?__('No contacts found matching your search'):__('No contacts found'))."</td></tr>";
}
foreach($slice as $idx=>$item){
$rowCls=($idx%2)?'row-classic':'row-alternate';
$badgeCls=($item['origin']==='public')?'badge-public':'badge-user';
$badgeLabel=($item['origin']==='public')?__('Public'):__('Users');
$memoHtml=!empty($item['memo'])
?" <span class='memo-icon' onclick='openCMemoAlert(this);event.preventDefault();' data-memo='".ns($item['memo'])."' data-name='".ns($item['name'])."' data-date='".ns($item['date']??'')."'><span class='fax-memo'>M</span></span>"
:"";
$canEdit=($item['origin']==='users'||$isAdmin);
echo"<tr class='$rowCls'>";
echo"<td>
<span class='badge $badgeCls'>".ns($badgeLabel)."</span>
<a href='fax_send.php?num=".urlencode($item['fax'])."' class='menulink'>
<strong>".ns($item['name'])."</strong>
</a>$memoHtml<br>
<span class='fax-date'>".ns($item['fax'])."</span>
</td>";
echo"<td class='icon'>";
if($canEdit){
echo"<a href='#' onclick='openContactModal(\"edit\",".ns(json_encode($item)).");return false;'>
<img src='img/box_submenu.png'>
</a>";
}
echo"</td>";
echo"<td class='icon'>";
if($canEdit){
echo"<a href='#' onclick='openContactDeleteDialog(\"{$item['id']}\",\"".ns($item['name'])."\",\"{$item['origin']}\");return false;'>
<img src='img/box_remove.png'>
</a>";
}
echo"</td>";
echo"</tr>";
}
if($totalPages>1){
$q='view='.urlencode($viewMode).'&q='.urlencode($search).'&sm='.($searchMemo?1:0);
echo"<tr><th colspan='3'><div class='pagination'>";
if($page>1){
echo"<input type='button' class='page-btn' value='«' onclick=\"location.href='?$q&page=1'\">";
echo"<input type='button' class='page-btn' value='‹' onclick=\"location.href='?$q&page=".($page-1)."'\">";
}
for($p=max(1,$page-2);$p<=min($totalPages,$page+2);$p++){
$c=($p==$page)?'page-btn current':'page-btn';
echo"<input type='button' class='$c' value='$p' onclick=\"location.href='?$q&page=$p'\">";
}
if($page<$totalPages){
echo"<input type='button' class='page-btn' value='›' onclick=\"location.href='?$q&page=".($page+1)."'\">";
echo"<input type='button' class='page-btn' value='»' onclick=\"location.href='?$q&page=$totalPages'\">";
}
echo"</div></th></tr>";
}
?>
</tbody>
</table>
</div>
</div>
</div>
<?php include('include/web/modal.php');?>
<?php include('include/web/footer.php');?>
</body>
</html>
