Order card: 'Message provider' and 'Call' buttons, also for a pending offer
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
e7de4f5893
commit
a848bb13e2
5 files changed
+49
-7
No files matched your search
@@ -37,6 +37,7 @@ const PATHS = {
|
||||
archive: 'M4 5h16v4H4zM5 9v10h14V9M10 13h4',
|
||||
bot: 'M6 9h12v10H6zM12 5v4M9.5 13.5v.01M14.5 13.5v.01M9 17h6M3 13v2M21 13v2',
|
||||
warn: 'M12 3l10 18H2zM12 10v5M12 18v.01',
|
||||
phone: 'M5 4h4l2 5-2.5 1.5a11 11 0 0 0 5 5L15 13l5 2v4a2 2 0 0 1-2 2A16 16 0 0 1 3 6a2 2 0 0 1 2-2z',
|
||||
} as const;
|
||||
export type IconName = keyof typeof PATHS;
|
||||
|
||||
|
||||
@@ -433,6 +433,8 @@ const ru = {
|
||||
'ord.client': 'Клиент',
|
||||
'ord.writeClient': 'Написать клиенту',
|
||||
'ord.writeProvider': 'Написать исполнителю',
|
||||
'ord.call': 'Позвонить',
|
||||
'ord.noPhone': 'Телефон исполнителя не указан — добавьте его в профиле',
|
||||
'ord.money': 'Деньги',
|
||||
'ord.base': 'Без скидки',
|
||||
'ord.discount': 'Скидка {pct}%',
|
||||
@@ -1075,6 +1077,8 @@ const en: Dict = {
|
||||
'ord.client': 'Client',
|
||||
'ord.writeClient': 'Message the client',
|
||||
'ord.writeProvider': 'Message the provider',
|
||||
'ord.call': 'Call',
|
||||
'ord.noPhone': 'No phone number — add it to the profile',
|
||||
'ord.money': 'Money',
|
||||
'ord.base': 'Before discount',
|
||||
'ord.discount': 'Discount {pct}%',
|
||||
@@ -1714,6 +1718,8 @@ const hy: Dict = {
|
||||
'ord.client': 'Հաճախորդ',
|
||||
'ord.writeClient': 'Գրել հաճախորդին',
|
||||
'ord.writeProvider': 'Գրել կատարողին',
|
||||
'ord.call': 'Զանգահարել',
|
||||
'ord.noPhone': 'Հեռախոսահամարը նշված չէ',
|
||||
'ord.money': 'Գումար',
|
||||
'ord.base': 'Առանց զեղչի',
|
||||
'ord.discount': 'Զեղչ {pct}%',
|
||||
|
||||
@@ -352,6 +352,12 @@
|
||||
}
|
||||
|
||||
/* подбор исполнителя */
|
||||
.bo-contact {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
.bo-pendingbox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -419,6 +419,7 @@ function ProviderPanel({ order: d, onChanged, canChat }: { order: OrderData; onC
|
||||
</div>
|
||||
|
||||
{d.provider ? (
|
||||
<>
|
||||
<div className="bo-person">
|
||||
<Avatar name={d.provider.name} id={d.provider.id} size={40} />
|
||||
<a href={`#/providers/${d.provider.id}`} style={{ minWidth: 0, color: 'inherit', textDecoration: 'none' }}>
|
||||
@@ -427,13 +428,11 @@ function ProviderPanel({ order: d, onChanged, canChat }: { order: OrderData; onC
|
||||
{[d.company?.name, d.provider.phone, d.provider.username && `@${d.provider.username}`].filter(Boolean).join(' · ') || '—'}
|
||||
</span>
|
||||
</a>
|
||||
{canChat && (
|
||||
<button type="button" className="bo-iconbtn" title={t('ord.writeProvider')} aria-label={t('ord.writeProvider')} onClick={() => chat.mutate({ providerId: d.provider!.id })}>
|
||||
<I name="chats" size={20} />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<ContactRow providerId={d.provider.id} phone={d.provider.phone} canChat={canChat} onChat={(id) => chat.mutate({ providerId: id })} busy={chat.isPending} />
|
||||
</>
|
||||
) : d.pending ? (
|
||||
<>
|
||||
<div className="bo-pendingbox">
|
||||
{d.pending.auto ? <I name="bot" size={20} /> : <I name="send" size={20} />}
|
||||
<span className="bo-grow">
|
||||
@@ -443,6 +442,8 @@ function ProviderPanel({ order: d, onChanged, canChat }: { order: OrderData; onC
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
{d.pending.providerId && <ContactRow providerId={d.pending.providerId} phone={d.pending.phone} canChat={canChat} onChat={(id) => chat.mutate({ providerId: id })} busy={chat.isPending} />}
|
||||
</>
|
||||
) : d.canAssign ? (
|
||||
<>
|
||||
<div className="bo-assignbar">
|
||||
@@ -496,6 +497,32 @@ function ProviderPanel({ order: d, onChanged, canChat }: { order: OrderData; onC
|
||||
);
|
||||
}
|
||||
|
||||
/** Связаться с исполнителем: чат в рабочем боте и звонок */
|
||||
function ContactRow({ providerId, phone, canChat, onChat, busy }: { providerId: string; phone: string | null; canChat: boolean; onChat: (id: string) => void; busy: boolean }) {
|
||||
const { t } = useT();
|
||||
return (
|
||||
<div className="bo-contact">
|
||||
{canChat && (
|
||||
<button type="button" className="bo-btn bo-btn--sm" onClick={() => onChat(providerId)} disabled={busy}>
|
||||
<I name="chats" size={16} />
|
||||
{t('ord.writeProvider')}
|
||||
</button>
|
||||
)}
|
||||
{phone ? (
|
||||
<a className="bo-btn bo-btn--ghost bo-btn--sm" href={`tel:${phone.replace(/[^\d+]/g, '')}`}>
|
||||
<I name="phone" size={16} />
|
||||
{t('ord.call')}
|
||||
</a>
|
||||
) : (
|
||||
<span className="bo-btn bo-btn--ghost bo-btn--sm" aria-disabled="true" title={t('ord.noPhone')} style={{ opacity: 0.45, cursor: 'default' }}>
|
||||
<I name="phone" size={16} />
|
||||
{t('ord.call')}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// ───── диалоги ─────
|
||||
|
||||
function RescheduleDialog({ order: d, onClose, onDone }: { order: OrderData; onClose: () => void; onDone: () => void }) {
|
||||
|
||||
Reference in new issue
Block a user