feature matching for clean extraction
This commit is contained in:
@@ -1,296 +1,411 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<!--
|
||||
MercadoPago shunt — config UI.
|
||||
|
||||
Brought onto the theme: it used to carry ~30 hardcoded hexes, its own reset,
|
||||
its own button and input rules, and zero var(--…), so it was the one page in
|
||||
the tree that could not follow a theme at all. Everything structural now comes
|
||||
from the baked parts; what is left below is this shunt's own.
|
||||
|
||||
A shunt serves this on its own port and cannot fetch soleprint's /theme.css,
|
||||
so the theme and the parts are baked in between markers by
|
||||
common/theme/bake.py. Run `make theme bake` after changing a class.
|
||||
|
||||
Only `base` and `panel` are baked here — this page has no split pane, so it
|
||||
carries no split.css and no split.js. That is the mechanism doing its job.
|
||||
-->
|
||||
<html lang="en" data-theme="soleprint">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>MercadoPago API (MOCK) - Configuration</title>
|
||||
<!-- theme:here -->
|
||||
<!-- theme:baked-defaults — generated by common/theme/bake.py; do not edit -->
|
||||
<style>
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: #111827;
|
||||
color: #e5e7eb;
|
||||
padding: 20px;
|
||||
}
|
||||
.container { max-width: 1200px; margin: 0 auto; }
|
||||
header {
|
||||
background: #0071f2;
|
||||
color: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
h1 { font-size: 1.5rem; font-weight: 600; margin-bottom: 8px; }
|
||||
.subtitle { opacity: 0.9; font-size: 0.875rem; }
|
||||
:root {
|
||||
--accent: #d4a574;
|
||||
--font-mono: "JetBrains Mono", "Cascadia Mono", Consolas, monospace;
|
||||
--font-size-base: 13px;
|
||||
--font-size-sm: 11px;
|
||||
--font-ui: Inter, "Segoe UI", system-ui, -apple-system, Arial, sans-serif;
|
||||
--label-spacing: 0.04em;
|
||||
--muted: #8888a0;
|
||||
--panel-border: 1px solid #2e2e38;
|
||||
--panel-header-height: 36px;
|
||||
--panel-radius: 6px;
|
||||
--space-1: 4px;
|
||||
--space-2: 8px;
|
||||
--space-3: 12px;
|
||||
--space-4: 16px;
|
||||
--space-6: 24px;
|
||||
--status-error: #f06565;
|
||||
--status-escalating: #f5a623;
|
||||
--status-idle: #555568;
|
||||
--status-live: #3ecf8e;
|
||||
--status-processing: #4f9cf9;
|
||||
--surface-0: #0d0d0f;
|
||||
--surface-1: #16161a;
|
||||
--surface-2: #1e1e24;
|
||||
--surface-3: #2e2e38;
|
||||
--text-dim: #555568;
|
||||
--text-primary: #e8e8f0;
|
||||
--text-secondary: #8888a0;
|
||||
}
|
||||
</style>
|
||||
<!-- /theme:baked-defaults -->
|
||||
<!-- theme:parts — generated by common/theme/bake.py; do not edit -->
|
||||
<style>
|
||||
/* part: base — common/theme/parts/base.css */
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--surface-0);
|
||||
color: var(--text-primary);
|
||||
font-family: var(--font-ui);
|
||||
font-size: var(--font-size-base);
|
||||
}
|
||||
|
||||
/* Opt in on <html>, <body> and the top element when the page is an app shell
|
||||
* that should fill the viewport. Left off, the page scrolls like a document —
|
||||
* which is what most ad-hoc vein pages actually want. */
|
||||
.fills {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
button {
|
||||
font-family: var(--font-ui);
|
||||
font-size: var(--font-size-base);
|
||||
color: var(--text-primary);
|
||||
background: var(--surface-2);
|
||||
border: var(--panel-border);
|
||||
border-radius: var(--panel-radius);
|
||||
padding: var(--space-1) var(--space-3);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:hover:not(:disabled) {
|
||||
background: var(--surface-3);
|
||||
}
|
||||
|
||||
button:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
font-family: var(--font-ui);
|
||||
font-size: var(--font-size-base);
|
||||
color: var(--text-primary);
|
||||
background: var(--surface-0);
|
||||
border: var(--panel-border);
|
||||
border-radius: 4px;
|
||||
padding: var(--space-1) var(--space-2);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--surface-3);
|
||||
border-radius: 5px;
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
/* part: panel — common/theme/parts/panel.css */
|
||||
.panel {
|
||||
position: relative;
|
||||
background: var(--surface-1);
|
||||
border: var(--panel-border);
|
||||
border-radius: var(--panel-radius);
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.panel-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
height: var(--panel-header-height);
|
||||
padding: 0 var(--space-3);
|
||||
background: var(--surface-2);
|
||||
border-bottom: var(--panel-border);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
font-family: var(--font-ui);
|
||||
font-size: var(--font-size-sm);
|
||||
font-weight: 600;
|
||||
color: var(--text-secondary);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.panel-actions {
|
||||
margin-left: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
}
|
||||
|
||||
.panel-status {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
background: var(--status-idle);
|
||||
}
|
||||
.panel-status.idle { background: var(--status-idle); }
|
||||
.panel-status.live { background: var(--status-live); }
|
||||
.panel-status.processing { background: var(--status-processing); }
|
||||
.panel-status.error { background: var(--status-error); }
|
||||
|
||||
.panel-body {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
padding: var(--space-2);
|
||||
min-height: 0;
|
||||
}
|
||||
</style>
|
||||
<!-- /theme:parts -->
|
||||
|
||||
<style>
|
||||
/* This page's own, and only its own. */
|
||||
body { padding: var(--space-6); }
|
||||
.container { max-width: 1100px; margin: 0 auto; }
|
||||
|
||||
header { margin-bottom: var(--space-6); }
|
||||
h1 { margin: 0; font-size: 20px; font-family: var(--font-ui); }
|
||||
.subtitle { color: var(--muted); font-size: 12px; margin-top: 4px; }
|
||||
|
||||
.mock-badge {
|
||||
display: inline-block;
|
||||
background: white;
|
||||
color: #0071f2;
|
||||
padding: 4px 12px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
margin-left: 12px;
|
||||
}
|
||||
.section {
|
||||
background: #1f2937;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.section-header {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 16px;
|
||||
color: #f9fafb;
|
||||
}
|
||||
.endpoint-list { display: flex; flex-direction: column; gap: 12px; }
|
||||
.endpoint-card {
|
||||
background: #374151;
|
||||
border: 2px solid transparent;
|
||||
border-radius: 6px;
|
||||
padding: 16px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.endpoint-card:hover { border-color: #0071f2; background: #4b5563; }
|
||||
.endpoint-card.active { border-color: #0071f2; background: #4b5563; }
|
||||
.endpoint-method {
|
||||
display: inline-block;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
margin-right: 8px;
|
||||
}
|
||||
.method-post { background: #10b981; color: white; }
|
||||
.method-get { background: #3b82f6; color: white; }
|
||||
.endpoint-path { font-family: monospace; font-size: 0.875rem; }
|
||||
.endpoint-desc { font-size: 0.75rem; color: #9ca3af; margin-top: 6px; }
|
||||
.form-group { margin-bottom: 16px; }
|
||||
.form-label {
|
||||
display: block;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
margin-bottom: 6px;
|
||||
color: #f9fafb;
|
||||
display: inline-block; margin-left: var(--space-2);
|
||||
padding: 2px 8px; border-radius: 3px;
|
||||
background: var(--status-escalating); color: var(--surface-0);
|
||||
font-size: 10px; font-weight: 600; text-transform: uppercase;
|
||||
letter-spacing: var(--label-spacing, .08em); vertical-align: middle;
|
||||
}
|
||||
.form-input, .form-textarea, .form-select {
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
background: #374151;
|
||||
border: 1px solid #4b5563;
|
||||
border-radius: 6px;
|
||||
color: #e5e7eb;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
.form-textarea { min-height: 200px; font-family: monospace; }
|
||||
.form-input:focus, .form-textarea:focus, .form-select:focus {
|
||||
outline: none;
|
||||
border-color: #0071f2;
|
||||
}
|
||||
.btn {
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
|
||||
.panel { margin-bottom: var(--space-4); }
|
||||
.lede { color: var(--muted); font-size: 12px; margin: 0 0 var(--space-3); }
|
||||
|
||||
.grid {
|
||||
display: grid; gap: var(--space-2);
|
||||
grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
|
||||
}
|
||||
.btn-primary {
|
||||
background: #0071f2;
|
||||
color: white;
|
||||
|
||||
/* Selectable cards — one treatment, used by both lists. */
|
||||
.card {
|
||||
padding: var(--space-3); cursor: pointer; text-align: left;
|
||||
background: var(--surface-2); border: var(--panel-border);
|
||||
border-radius: var(--panel-radius);
|
||||
}
|
||||
.btn-primary:hover { background: #005ac1; }
|
||||
.btn-secondary {
|
||||
background: #4b5563;
|
||||
color: #e5e7eb;
|
||||
margin-left: 8px;
|
||||
.card:hover:not(:disabled) { border-color: var(--accent); background: var(--surface-3); }
|
||||
.card.on { border-color: var(--accent); background: var(--surface-3); }
|
||||
.card-name { font-weight: 600; color: var(--text-primary); margin-bottom: 4px; }
|
||||
.card-desc { font-size: 11px; color: var(--muted); }
|
||||
|
||||
.verb {
|
||||
font-size: 10px; font-weight: 600; padding: 1px 6px;
|
||||
border-radius: 3px; border: 1px solid currentColor; margin-right: var(--space-2);
|
||||
}
|
||||
.btn-secondary:hover { background: #6b7280; }
|
||||
.status-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||
gap: 12px;
|
||||
.verb.POST { color: var(--status-live); }
|
||||
.verb.GET { color: var(--status-processing); }
|
||||
.path { font-family: var(--font-mono); font-size: 12px; }
|
||||
|
||||
.field { margin-bottom: var(--space-3); }
|
||||
.field label {
|
||||
display: block; margin-bottom: 4px; font-size: 11px;
|
||||
color: var(--muted); text-transform: uppercase; letter-spacing: .04em;
|
||||
}
|
||||
.status-option {
|
||||
background: #374151;
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
border: 2px solid transparent;
|
||||
.field input, .field textarea { width: 100%; font-family: var(--font-mono); font-size: 12px; }
|
||||
.field textarea { min-height: 180px; resize: vertical; }
|
||||
|
||||
.actions { display: flex; gap: var(--space-2); }
|
||||
.primary { background: var(--accent); color: var(--surface-0); border-color: transparent; }
|
||||
.primary:hover:not(:disabled) { opacity: .9; background: var(--accent); }
|
||||
|
||||
.url {
|
||||
font-family: var(--font-mono); font-size: 12px; user-select: all;
|
||||
padding: var(--space-2) var(--space-3);
|
||||
background: var(--surface-0); border: var(--panel-border);
|
||||
border-radius: var(--panel-radius);
|
||||
}
|
||||
.status-option:hover { border-color: #0071f2; }
|
||||
.status-option.selected { border-color: #0071f2; background: #4b5563; }
|
||||
.status-name { font-weight: 600; color: #f9fafb; margin-bottom: 4px; }
|
||||
.status-desc { font-size: 0.75rem; color: #9ca3af; }
|
||||
.note { color: var(--text-dim); font-size: 11px; margin: var(--space-2) 0 0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<header>
|
||||
<h1>MercadoPago <span class="mock-badge">MOCK</span></h1>
|
||||
<div class="subtitle">Configure mock payment responses and behavior</div>
|
||||
</header>
|
||||
|
||||
<!-- Payment Status Configuration -->
|
||||
<div class="section">
|
||||
<div class="section-header">Default Payment Status</div>
|
||||
<p style="color: #9ca3af; margin-bottom: 16px;">Choose what status new payments should return:</p>
|
||||
<div class="status-grid">
|
||||
<div class="status-option selected" onclick="selectStatus('approved')">
|
||||
<div class="status-name">Approved</div>
|
||||
<div class="status-desc">Payment successful</div>
|
||||
</div>
|
||||
<div class="status-option" onclick="selectStatus('rejected')">
|
||||
<div class="status-name">Rejected</div>
|
||||
<div class="status-desc">Payment failed</div>
|
||||
</div>
|
||||
<div class="status-option" onclick="selectStatus('pending')">
|
||||
<div class="status-name">Pending</div>
|
||||
<div class="status-desc">Awaiting confirmation</div>
|
||||
</div>
|
||||
<div class="status-option" onclick="selectStatus('in_process')">
|
||||
<div class="status-name">In Process</div>
|
||||
<div class="status-desc">Being processed</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<header>
|
||||
<h1>MercadoPago <span class="mock-badge">mock</span></h1>
|
||||
<div class="subtitle">Configure mock payment responses and behaviour</div>
|
||||
</header>
|
||||
|
||||
<div class="panel">
|
||||
<div class="panel-header">
|
||||
<span class="panel-title">Default payment status</span>
|
||||
<span class="panel-status live"></span>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p class="lede">What status new payments should return.</p>
|
||||
<div class="grid" id="statuses"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Endpoint Configuration -->
|
||||
<div class="section">
|
||||
<div class="section-header">Configure Endpoint Responses</div>
|
||||
<div class="endpoint-list">
|
||||
<div class="endpoint-card" onclick="selectEndpoint('POST', '/checkout/preferences', 'preference')">
|
||||
<div>
|
||||
<span class="endpoint-method method-post">POST</span>
|
||||
<span class="endpoint-path">/checkout/preferences</span>
|
||||
</div>
|
||||
<div class="endpoint-desc">Create payment preference (Checkout Pro)</div>
|
||||
</div>
|
||||
<div class="endpoint-card" onclick="selectEndpoint('POST', '/v1/payments', 'payment')">
|
||||
<div>
|
||||
<span class="endpoint-method method-post">POST</span>
|
||||
<span class="endpoint-path">/v1/payments</span>
|
||||
</div>
|
||||
<div class="endpoint-desc">Create payment (Checkout API)</div>
|
||||
</div>
|
||||
<div class="endpoint-card" onclick="selectEndpoint('GET', '/v1/payments/{id}', 'payment_get')">
|
||||
<div>
|
||||
<span class="endpoint-method method-get">GET</span>
|
||||
<span class="endpoint-path">/v1/payments/{id}</span>
|
||||
</div>
|
||||
<div class="endpoint-desc">Get payment details</div>
|
||||
</div>
|
||||
<div class="endpoint-card" onclick="selectEndpoint('POST', '/oauth/token', 'oauth')">
|
||||
<div>
|
||||
<span class="endpoint-method method-post">POST</span>
|
||||
<span class="endpoint-path">/oauth/token</span>
|
||||
</div>
|
||||
<div class="endpoint-desc">OAuth token exchange/refresh</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel">
|
||||
<div class="panel-header">
|
||||
<span class="panel-title">Endpoint responses</span>
|
||||
<span class="panel-actions"><span class="card-desc" id="count"></span></span>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="grid" id="endpoints"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Response Editor -->
|
||||
<div class="section" id="responseEditor" style="display: none;">
|
||||
<div class="section-header">Edit Response</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Endpoint</label>
|
||||
<input class="form-input" id="endpointDisplay" readonly>
|
||||
<div class="panel" id="editor" hidden>
|
||||
<div class="panel-header">
|
||||
<span class="panel-title">Edit response</span>
|
||||
<span class="panel-status processing"></span>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="field">
|
||||
<label for="endpointDisplay">Endpoint</label>
|
||||
<input id="endpointDisplay" readonly>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Mock Response (JSON)</label>
|
||||
<textarea class="form-textarea" id="responseJson" placeholder='{"id": "123456", "status": "approved", "_mock": "MercadoPago"}'></textarea>
|
||||
<div class="field">
|
||||
<label for="responseJson">Mock response (JSON)</label>
|
||||
<textarea id="responseJson"></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">HTTP Status Code</label>
|
||||
<input type="number" class="form-input" id="statusCode" value="200">
|
||||
<div class="field">
|
||||
<label for="statusCode">HTTP status code</label>
|
||||
<input type="number" id="statusCode" value="200">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Delay (ms)</label>
|
||||
<input type="number" class="form-input" id="delay" value="0">
|
||||
<div class="field">
|
||||
<label for="delay">Delay (ms)</label>
|
||||
<input type="number" id="delay" value="0">
|
||||
</div>
|
||||
<div>
|
||||
<button class="btn btn-primary" onclick="saveResponse()">Save Response</button>
|
||||
<button class="btn btn-secondary" onclick="closeEditor()">Cancel</button>
|
||||
<div class="actions">
|
||||
<button class="primary" onclick="saveResponse()">Save response</button>
|
||||
<button onclick="closeEditor()">Cancel</button>
|
||||
</div>
|
||||
<p class="note">Saving is not implemented yet — it was not implemented before this
|
||||
page was rebrought onto the theme either, and pretending otherwise would be worse.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Test -->
|
||||
<div class="section">
|
||||
<div class="section-header">Quick Test</div>
|
||||
<p style="color: #9ca3af; margin-bottom: 12px;">Test endpoint URL to hit for configured responses:</p>
|
||||
<div class="form-input" style="background: #374151; user-select: all;">
|
||||
http://localhost:8006/v1/payments
|
||||
</div>
|
||||
<div class="panel">
|
||||
<div class="panel-header"><span class="panel-title">Quick test</span></div>
|
||||
<div class="panel-body">
|
||||
<p class="lede">Hit this URL to get the configured responses.</p>
|
||||
<div class="url">http://localhost:8006/v1/payments</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let selectedEndpoint = null;
|
||||
let selectedPaymentStatus = 'approved';
|
||||
<script>
|
||||
const STATUSES = [
|
||||
{ key: 'approved', name: 'Approved', desc: 'Payment successful' },
|
||||
{ key: 'rejected', name: 'Rejected', desc: 'Payment failed' },
|
||||
{ key: 'pending', name: 'Pending', desc: 'Awaiting confirmation' },
|
||||
{ key: 'in_process', name: 'In Process', desc: 'Being processed' },
|
||||
];
|
||||
|
||||
function selectStatus(status) {
|
||||
selectedPaymentStatus = status;
|
||||
document.querySelectorAll('.status-option').forEach(opt => opt.classList.remove('selected'));
|
||||
event.currentTarget.classList.add('selected');
|
||||
}
|
||||
const ENDPOINTS = [
|
||||
{ verb: 'POST', path: '/checkout/preferences', type: 'preference', desc: 'Create payment preference (Checkout Pro)' },
|
||||
{ verb: 'POST', path: '/v1/payments', type: 'payment', desc: 'Create payment (Checkout API)' },
|
||||
{ verb: 'GET', path: '/v1/payments/{id}', type: 'payment_get', desc: 'Get payment details' },
|
||||
{ verb: 'POST', path: '/oauth/token', type: 'oauth', desc: 'OAuth token exchange/refresh' },
|
||||
];
|
||||
|
||||
function selectEndpoint(method, path, type) {
|
||||
selectedEndpoint = {method, path, type};
|
||||
document.querySelectorAll('.endpoint-card').forEach(c => c.classList.remove('active'));
|
||||
event.currentTarget.classList.add('active');
|
||||
document.getElementById('responseEditor').style.display = 'block';
|
||||
document.getElementById('endpointDisplay').value = `${method} ${path}`;
|
||||
document.getElementById('responseJson').value = getDefaultResponse(type);
|
||||
}
|
||||
let paymentStatus = 'approved';
|
||||
let selected = null;
|
||||
|
||||
function getDefaultResponse(type) {
|
||||
const defaults = {
|
||||
preference: JSON.stringify({
|
||||
"id": "123456-pref-id",
|
||||
"init_point": "https://www.mercadopago.com.ar/checkout/v1/redirect?pref_id=123456",
|
||||
"sandbox_init_point": "https://sandbox.mercadopago.com.ar/checkout/v1/redirect?pref_id=123456",
|
||||
"_mock": "MercadoPago"
|
||||
}, null, 2),
|
||||
payment: JSON.stringify({
|
||||
"id": 123456,
|
||||
"status": selectedPaymentStatus,
|
||||
"status_detail": selectedPaymentStatus === 'approved' ? 'accredited' : 'cc_rejected_other_reason',
|
||||
"transaction_amount": 1500,
|
||||
"currency_id": "ARS",
|
||||
"_mock": "MercadoPago"
|
||||
}, null, 2),
|
||||
payment_get: JSON.stringify({
|
||||
"id": 123456,
|
||||
"status": "approved",
|
||||
"status_detail": "accredited",
|
||||
"transaction_amount": 1500,
|
||||
"_mock": "MercadoPago"
|
||||
}, null, 2),
|
||||
oauth: JSON.stringify({
|
||||
"access_token": "APP_USR-123456-mock-token",
|
||||
"token_type": "Bearer",
|
||||
"expires_in": 15552000,
|
||||
"refresh_token": "TG-123456-mock-refresh",
|
||||
"_mock": "MercadoPago"
|
||||
}, null, 2)
|
||||
};
|
||||
return defaults[type] || '{}';
|
||||
}
|
||||
const $ = (id) => document.getElementById(id);
|
||||
|
||||
function saveResponse() {
|
||||
alert('Mock response saved (feature pending implementation)');
|
||||
}
|
||||
function pick(container, el) {
|
||||
container.querySelectorAll('.card').forEach((c) => c.classList.remove('on'));
|
||||
el.classList.add('on');
|
||||
}
|
||||
|
||||
function closeEditor() {
|
||||
document.getElementById('responseEditor').style.display = 'none';
|
||||
selectedEndpoint = null;
|
||||
document.querySelectorAll('.endpoint-card').forEach(c => c.classList.remove('active'));
|
||||
}
|
||||
</script>
|
||||
STATUSES.forEach((s, i) => {
|
||||
const b = document.createElement('button');
|
||||
b.className = 'card' + (i === 0 ? ' on' : '');
|
||||
b.innerHTML = '<div class="card-name"></div><div class="card-desc"></div>';
|
||||
b.firstChild.textContent = s.name;
|
||||
b.lastChild.textContent = s.desc;
|
||||
b.onclick = () => { paymentStatus = s.key; pick($('statuses'), b); };
|
||||
$('statuses').appendChild(b);
|
||||
});
|
||||
|
||||
ENDPOINTS.forEach((e) => {
|
||||
const b = document.createElement('button');
|
||||
b.className = 'card';
|
||||
b.innerHTML = '<div><span class="verb ' + e.verb + '">' + e.verb + '</span>' +
|
||||
'<span class="path"></span></div><div class="card-desc"></div>';
|
||||
b.querySelector('.path').textContent = e.path;
|
||||
b.lastChild.textContent = e.desc;
|
||||
b.onclick = () => {
|
||||
selected = e;
|
||||
pick($('endpoints'), b);
|
||||
$('editor').hidden = false;
|
||||
$('endpointDisplay').value = e.verb + ' ' + e.path;
|
||||
$('responseJson').value = defaultResponse(e.type);
|
||||
};
|
||||
$('endpoints').appendChild(b);
|
||||
});
|
||||
|
||||
$('count').textContent = ENDPOINTS.length + ' endpoints';
|
||||
|
||||
function defaultResponse(type) {
|
||||
const bodies = {
|
||||
preference: {
|
||||
id: '123456-pref-id',
|
||||
init_point: 'https://www.mercadopago.com.ar/checkout/v1/redirect?pref_id=123456',
|
||||
sandbox_init_point: 'https://sandbox.mercadopago.com.ar/checkout/v1/redirect?pref_id=123456',
|
||||
_mock: 'MercadoPago',
|
||||
},
|
||||
payment: {
|
||||
id: 123456,
|
||||
status: paymentStatus,
|
||||
status_detail: paymentStatus === 'approved' ? 'accredited' : 'cc_rejected_other_reason',
|
||||
transaction_amount: 1500,
|
||||
currency_id: 'ARS',
|
||||
_mock: 'MercadoPago',
|
||||
},
|
||||
payment_get: {
|
||||
id: 123456, status: 'approved', status_detail: 'accredited',
|
||||
transaction_amount: 1500, _mock: 'MercadoPago',
|
||||
},
|
||||
oauth: {
|
||||
access_token: 'APP_USR-123456-mock-token', token_type: 'Bearer',
|
||||
expires_in: 15552000, refresh_token: 'TG-123456-mock-refresh', _mock: 'MercadoPago',
|
||||
},
|
||||
};
|
||||
return JSON.stringify(bodies[type] || {}, null, 2);
|
||||
}
|
||||
|
||||
function saveResponse() {
|
||||
alert('Mock response saved (feature pending implementation)');
|
||||
}
|
||||
|
||||
function closeEditor() {
|
||||
$('editor').hidden = true;
|
||||
selected = null;
|
||||
document.querySelectorAll('#endpoints .card').forEach((c) => c.classList.remove('on'));
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user