Files
customerTicket/design-prototypes/chaharsu/payment-services.js
T
2026-10-05 12:36:58 +03:30

160 lines
11 KiB
JavaScript

/* Local UI prototype. No requests, storage, upload or database writes.
Keep opaque notice IDs in links. Production must check ownership server-side. */
(() => {
'use strict';
const version=document.documentElement.dataset.staticVersion;
const notices=window.chaharsuPaymentNotices || [];
const byId=id=>notices.find(notice=>notice.id===id);
const query=selector=>document.querySelector(selector);
const money=notice=>new Intl.NumberFormat('fa-IR').format(Number(notice.amount))+' '+notice.currency;
const fields=notice=>[
['مبلغ واریز',money(notice),notice.amount,true],
['نام بانک',notice.bank,notice.bank,false],
['صاحب حساب',notice.holder,notice.holder,false],
['شماره حساب',notice.account,notice.account,true],
['شماره شبا',notice.iban,notice.iban,true],
['شماره کارت',notice.card || 'اعلام نشده',notice.card,true],
['شناسهٔ واریز',notice.deposit || 'اعلام نشده',notice.deposit,true],
['شماره فاکتور',notice.invoice || 'اعلام نشده',notice.invoice,true],
['توضیحات کارشناس',notice.description || 'توضیحی ثبت نشده',notice.description,false]
];
const link=(page,id)=>page+'?v='+version+(id?'&notice='+encodeURIComponent(id):'');
function copyTextFor(notice){
return ['اطلاعات نمایشی چهارسو — شماره‌ها ساختگی و غیرقابل پرداخت‌اند.',notice.title,
'شمارهٔ اعلامیه: '+notice.id,'تاریخ اعلام: '+notice.issued,'اعلام‌کننده: '+notice.author,
...fields(notice).map(([label,value])=>label+': '+value)].join('\n');
}
let feedbackTimer;
function feedback(message){
clearTimeout(feedbackTimer);query('#copy-feedback').textContent=message;
feedbackTimer=setTimeout(()=>{query('#copy-feedback').textContent='';},6500);
}
function fallbackCopy(text){
const area=document.createElement('textarea');area.value=text;area.setAttribute('aria-label','متن کپی');
area.style.cssText='position:fixed;top:0;left:0;width:1px;height:1px;opacity:0';
document.body.append(area);area.select();let copied=false;
try{copied=document.execCommand('copy');}catch(error){copied=false;}finally{area.remove();}
return copied;
}
async function copyValue(text,label){
const previousFocus=document.activeElement;
let copied=false;
try{if(navigator.clipboard?.writeText){await navigator.clipboard.writeText(text);copied=true;}}catch(error){copied=false;}
if(!copied)copied=fallbackCopy(text);
previousFocus?.focus({preventScroll:true});
if(copied){feedback(label+' کپی شد. اکنون می‌توانید آن را جای‌گذاری کنید.');return;}
feedback('کپی خودکار ممکن نشد؛ متن آمادهٔ انتخاب است.');
const dialog=query('#manual-copy');query('#manual-copy-text').value=text;
dialog.showModal();query('#manual-copy-text').focus();query('#manual-copy-text').select();
}
function appendField(container,field,copyable=true){
const [label,value,raw,ltr]=field;
const row=document.createElement('div');row.className='payment-field';
const term=document.createElement('dt');term.textContent=label;
const definition=document.createElement('dd');definition.textContent=value;
if(ltr){definition.dir='ltr';definition.className='numeric-value';}
row.append(term,definition);
if(copyable && raw){
const button=document.createElement('button');button.type='button';button.className='copy-field';
button.textContent='کپی';button.setAttribute('aria-label','کپی '+label);
button.addEventListener('click',()=>copyValue(raw,label));row.append(button);
}else{row.classList.add('no-copy');}
container.append(row);
}
function makeNotice(notice){
const article=query('#notice-template').content.firstElementChild.cloneNode(true);
const button=article.querySelector('.notice-toggle');const detail=article.querySelector('.notice-detail');
article.id=notice.id;button.id='toggle-'+notice.id;detail.id='details-'+notice.id;
button.setAttribute('aria-controls',detail.id);detail.setAttribute('aria-labelledby',button.id);
article.querySelector('.notice-title').textContent=notice.title;
article.querySelector('.notice-amount').textContent=money(notice);
article.querySelector('.notice-meta').textContent='فاکتور '+notice.invoice+' · '+notice.issued;
const state=article.querySelector('.payment-state');
state.textContent=notice.receiptReceived?'فیش در حال بررسی':'در انتظار فیش';
state.classList.toggle('received',notice.receiptReceived);
article.querySelector('.notice-author').textContent='اعلام‌شده توسط '+notice.author;
article.querySelector('.notice-date').textContent='اعلامیهٔ '+notice.id;
article.querySelector('.notice-bank-name').textContent=notice.bank;
article.querySelector('.notice-holder').textContent=notice.holder;
const container=article.querySelector('.essential-fields');
// Compact UI is a projection; copyTextFor always uses the full notice, including all supplementary information.
const allFields=fields(notice);
[0,3,4,5,6].forEach(index=>{const field=allFields[index];if(field[2])appendField(container,field);});
const extra=article.querySelector('.extra-fields');
[7,8].forEach(index=>appendField(extra,allFields[index],false));
article.querySelector('.copy-complete').addEventListener('click',()=>copyValue(copyTextFor(notice),'اطلاعات کامل'));
article.querySelector('.receipt-link').href=link('payment-receipt.html',notice.id);
button.addEventListener('click',()=>toggleNotice(article,notice));
return article;
}
function openNotice(article){
document.querySelectorAll('.payment-notice').forEach(item=>{
const open=item===article;item.querySelector('.notice-toggle').setAttribute('aria-expanded',String(open));
item.querySelector('.notice-detail').hidden=!open;
});
}
function toggleNotice(article,notice){
const open=article.querySelector('.notice-toggle').getAttribute('aria-expanded')==='true';
openNotice(open?null:article);
const url=new URL(location.href);url.searchParams.delete('notice');
if(!open)url.searchParams.set('notice',notice.id);
history.replaceState(null,'',url.href);
}
function initAccounts(){
const container=query('#payment-notices');notices.forEach(notice=>container.append(makeNotice(notice)));
const search=query('#notice-search');
function filter(){
const term=search.value.trim().toLocaleLowerCase('fa');let count=0;
notices.forEach(notice=>{
const article=document.getElementById(notice.id);
const match=[notice.title,notice.invoice,notice.bank,notice.id].join(' ').toLocaleLowerCase('fa').includes(term);
article.hidden=!match;if(match)count++;
});
query('#notice-count').textContent=new Intl.NumberFormat('fa-IR').format(count)+' مورد';
query('#notices-empty').hidden=count!==0;
}
search.addEventListener('input',filter);
query('#clear-search').addEventListener('click',()=>{search.value='';filter();search.focus();});filter();
if(!notices.length){query('#notices-empty h3').textContent='هنوز اطلاعات واریزی برای شما ارسال نشده است';query('#notices-empty p').textContent='پس از اعلام کارشناس، اطلاعات هر واریز در این بخش نمایش داده می‌شود.';query('#clear-search').hidden=true;search.disabled=true;}
const id=new URLSearchParams(location.search).get('notice');
if(id){const notice=byId(id);if(notice){openNotice(document.getElementById(id));}else{feedback('این اعلامیه در دسترس نیست. فقط موارد اعلام‌شده به شما نمایش داده می‌شوند.');}}
}
function initReceipt(){
const select=query('#notice-select');
notices.forEach(notice=>{const option=document.createElement('option');option.value=notice.id;option.textContent=notice.invoice+' · '+money(notice)+' · '+notice.bank;select.append(option);});
if(!notices.length)query('#notice-selection-help').textContent='هنوز اعلامیه‌ای ندارید؛ از کارشناس بخواهید ایجاد کند یا واریز مستقل را انتخاب کنید.';
const modes=document.querySelectorAll('input[name="receipt-mode"]');
let invalid=false;
function sync(){
const linked=query('input[name="receipt-mode"]:checked').value==='linked';
query('#linked-payment').hidden=!linked;query('#independent-help').hidden=linked;
select.disabled=!linked;select.required=linked;
if(!linked){select.value='';invalid=false;}
const notice=linked?byId(select.value):null;
query('#notice-invalid').hidden=!invalid;
select.setAttribute('aria-invalid',String(invalid));
query('#selected-payment').hidden=!notice;
query('#selected-fields').replaceChildren();
if(notice){
query('#selected-title').textContent=notice.title;
[['مبلغ اعلام‌شده',money(notice),false],['شماره فاکتور',notice.invoice,true],['بانک مقصد',notice.bank,false],['شناسهٔ واریز',notice.deposit || 'اعلام نشده',true]].forEach(([label,value,ltr])=>appendField(query('#selected-fields'),[label,value,null,ltr],false));
query('#selected-details').href=link('bank-accounts.html',notice.id);
}
query('#receipt-summary').textContent=linked?(notice?'این فیش به فاکتور '+notice.invoice+' مرتبط می‌شود.':'برای فیش مرتبط، ابتدا واریز اعلام‌شده را انتخاب کنید.'):'نوع فیش: واریز مستقل؛ ارتباطی با اعلامیه‌های قبلی ندارد.';
const url=new URL(location.href);url.searchParams.delete('notice');if(notice)url.searchParams.set('notice',notice.id);
history.replaceState(null,'',url.href);
}
const incoming=new URLSearchParams(location.search).get('notice');
if(incoming){query('input[value="linked"]').checked=true;if(byId(incoming)){select.value=incoming;}else{invalid=true;}}
modes.forEach(mode=>mode.addEventListener('change',sync));select.addEventListener('change',()=>{invalid=false;sync();});sync();
const input=query('#receipt-file');const selection=query('#file-selection');const status=query('#file-status');
input.addEventListener('change',()=>{const file=input.files[0];selection.hidden=!file;status.textContent=file?'فایل انتخاب‌شده: '+file.name+' · ارسال نشده':'';});
query('#clear-file').addEventListener('click',()=>{input.value='';selection.hidden=true;status.textContent='';input.focus();});
query('#receipt-form').addEventListener('submit',event=>event.preventDefault());
}
query('#select-copy-text').addEventListener('click',()=>{query('#manual-copy-text').focus();query('#manual-copy-text').select();});
query('#close-copy').addEventListener('click',()=>query('#manual-copy').close());
if(document.body.dataset.financePage==='accounts')initAccounts();
if(document.body.dataset.financePage==='receipt')initReceipt();
})();