The extra cropped-result panel duplicated what the crop pad already shows and the cleaned image supersedes it. Removes the panel, its state, the pointer- release refresh handlers and the app.js plumbing. The crop result is still uploaded (croppa stays the source when nothing is cleaned).
182 lines
8.8 KiB
HTML
182 lines
8.8 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Image Cropper · YOUreka Tools</title>
|
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600;700&display=swap">
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@carbon/styles@1.69.0/css/styles.min.css">
|
|
<link rel="stylesheet" href="/assets/style.css">
|
|
<link rel="icon" type="image/png" href="/assets/youreka-favicon.png">
|
|
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.min.js"></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/vue-croppa@1.3.8/dist/vue-croppa.min.js"></script>
|
|
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vue-croppa@1.3.8/dist/vue-croppa.min.css">
|
|
<script type="module" src="https://1.www.s81c.com/common/carbon/web-components/version/v2.50.0/ui-shell.min.js"></script>
|
|
<script type="module" src="https://1.www.s81c.com/common/carbon/web-components/version/v2.50.0/modal.min.js"></script>
|
|
<script type="module" src="https://1.www.s81c.com/common/carbon/web-components/version/v2.50.0/button.min.js"></script>
|
|
<script type="module" src="https://1.www.s81c.com/common/carbon/web-components/version/v2.50.0/notification.min.js"></script>
|
|
<script type="module" src="https://1.www.s81c.com/common/carbon/web-components/version/v2.50.0/tag.min.js"></script>
|
|
<style>
|
|
.croppa-pad { border: 1px solid var(--cds-border-strong, #8d8d8d); width: 252px; height: 270px; overflow: hidden; background: var(--cds-field, #f4f4f4); }
|
|
.croppa-pad img { width: 250px; display: block; }
|
|
.review-options .form-check { margin-bottom: 0.35rem; }
|
|
</style>
|
|
</head>
|
|
<body class="app cds--g100">
|
|
<div id="app">
|
|
<!--app-header-->
|
|
|
|
<main class="container" v-cloak v-if="session">
|
|
<div class="page-head">
|
|
<div>
|
|
<h1>Image Cropper</h1>
|
|
<p class="sub">Review, crop and save identity photos</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- notifications -->
|
|
<div class="toast-viewport" aria-live="polite">
|
|
<cds-inline-notification v-for="t in toasts" v-bind:key="t.id" v-bind:kind="t.kind"
|
|
v-bind:title="t.title" v-bind:subtitle="t.caption" low-contrast
|
|
v-on:cds-notification-closed="removeToast(t.id)"></cds-inline-notification>
|
|
</div>
|
|
|
|
<!-- 1 · load -->
|
|
<section class="card panel">
|
|
<div class="panel-head">
|
|
<span class="step-chip">1</span>
|
|
<h2>Load a picture</h2>
|
|
<span class="hint" v-if="message && message.message">Working on {{ message.message.caption || '(no caption)' }} · {{ message.message.domain }}</span>
|
|
</div>
|
|
<div class="row-gap">
|
|
<cds-button v-bind:disabled="busy.load" v-on:click="loadPicture('next')">
|
|
<span v-if="!busy.load">Load next queued</span>
|
|
<span v-else>Loading…</span>
|
|
</cds-button>
|
|
<cds-button kind="secondary" v-bind:disabled="busy.load" v-on:click="loadPicture('by-id')">Load by upload ID</cds-button>
|
|
<cds-button kind="ghost" v-if="message && message.message" v-on:click="reset">Clear</cds-button>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- 2 · review & crop -->
|
|
<section class="card panel" v-if="message && message.message">
|
|
<div class="panel-head">
|
|
<span class="step-chip">2</span>
|
|
<h2>Review picture</h2>
|
|
<span class="hint">Accept, or reject with reasons</span>
|
|
</div>
|
|
|
|
<dl class="details">
|
|
<div><dt>Phone</dt><dd>{{ message.message.caption || '—' }}</dd></div>
|
|
<div><dt>Domain</dt><dd>{{ message.message.domain }}</dd></div>
|
|
<div v-if="agent"><dt>Agent</dt><dd>{{ agent.name }} <span class="faint">{{ agent.phone }}</span></dd></div>
|
|
<div v-if="message.message.process">
|
|
<dt>Process</dt>
|
|
<dd>{{ message.message.process.variables.name }} <cds-tag type="blue">{{ message.message.process.variables.environment }}</cds-tag></dd>
|
|
</div>
|
|
</dl>
|
|
|
|
<div class="editor-grid mt-2">
|
|
<div class="editor-media">
|
|
<label class="cds--label">Original — crop it</label>
|
|
<div class="croppa-pad mt-1">
|
|
<croppa ref="croppa" v-model="myCroppa" :show-remove-button="false" :width="250" :height="267.44" :quality="2">
|
|
<img slot="initial" crossOrigin="anonymous" :src="message.message.file_url" style="width: 300px">
|
|
</croppa>
|
|
</div>
|
|
<template v-if="cleanedImage">
|
|
<label class="cds--label mt-2" style="display:block;">Cleaned preview</label>
|
|
<div class="croppa-pad mt-1">
|
|
<img :src="cleanedImage" alt="cleaned preview">
|
|
</div>
|
|
<cds-button kind="ghost" class="mt-1" v-on:click="cleanedImage = null">Remove cleaned image</cds-button>
|
|
</template>
|
|
</div>
|
|
|
|
<div class="editor-controls">
|
|
<div class="row-gap" style="align-items:flex-end;">
|
|
<div style="min-width:200px;">
|
|
<label class="cds--label" for="requiresCleaning">Requires cleaning?</label>
|
|
<select id="requiresCleaning" class="cds--select-input" v-model="requiresCleaning">
|
|
<option value="">--Choose--</option>
|
|
<option value="Yes">Yes</option>
|
|
<option value="No">No</option>
|
|
</select>
|
|
</div>
|
|
<cds-button v-if="requiresCleaning === 'Yes'" v-bind:disabled="busy.clean" v-on:click="cleanImage">
|
|
<span v-if="!busy.clean">Clean background</span>
|
|
<span v-else>Cleaning…</span>
|
|
</cds-button>
|
|
</div>
|
|
|
|
<hr class="mt-2">
|
|
|
|
<div class="row-gap" v-if="!reviewed">
|
|
<cds-button v-on:click="reviewed = true; accepted = true">Accept picture</cds-button>
|
|
<cds-button kind="danger" v-on:click="reviewed = true; accepted = false">Reject picture</cds-button>
|
|
</div>
|
|
|
|
<div v-if="reviewed && accepted" class="mt-2">
|
|
<div class="row-gap" style="align-items:flex-end;">
|
|
<div style="min-width:150px; max-width:200px;">
|
|
<label class="cds--label" for="otpSave">OTP</label>
|
|
<input id="otpSave" class="cds--text-input" v-model.trim="otp" autocomplete="one-time-code">
|
|
</div>
|
|
<cds-button v-bind:disabled="!canSave" v-on:click="saveChanges">
|
|
<span v-if="!busy.save">Crop and upload picture</span>
|
|
<span v-else>Saving…</span>
|
|
</cds-button>
|
|
<cds-button kind="ghost" v-on:click="reviewed = false">Change review</cds-button>
|
|
</div>
|
|
</div>
|
|
|
|
<div v-if="reviewed && !accepted" class="mt-2">
|
|
<label class="cds--label">Please state why this picture is not good enough.</label>
|
|
<div class="review-options mt-1" v-for="item in reviewOptions" v-bind:key="item.index">
|
|
<div class="cds--form-item cds--checkbox-wrapper">
|
|
<input class="cds--checkbox" type="checkbox" v-bind:id="'reason-' + item.index"
|
|
v-bind:value="item.name" v-model="selectedReviewOptions">
|
|
<label class="cds--checkbox-label" v-bind:for="'reason-' + item.index">
|
|
<span class="cds--checkbox-label-text">{{ item.name }}</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="mt-1" style="max-width:480px;" v-if="otherOptionSelected">
|
|
<label class="cds--label" for="otherReviewOption">Others (please specify).</label>
|
|
<div class="cds--text-area__wrapper">
|
|
<textarea id="otherReviewOption" rows="3" class="cds--text-area" v-model="otherReviewOption"></textarea>
|
|
</div>
|
|
</div>
|
|
<div class="row-gap mt-2">
|
|
<cds-button kind="danger" v-bind:disabled="!canReview" v-on:click="reviewPicture()">
|
|
<span v-if="!busy.review">Send review</span>
|
|
<span v-else>Sending…</span>
|
|
</cds-button>
|
|
<cds-button kind="ghost" v-if="!message.message.process" v-bind:disabled="!canReview" v-on:click="removeFromQueue">Dequeue only</cds-button>
|
|
<cds-button kind="ghost" v-on:click="reviewed = false">Change review</cds-button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</main>
|
|
|
|
<main class="container" v-cloak v-if="loading && !session">
|
|
<div class="narrow center-v">
|
|
<div class="card panel" style="text-align:center;">Loading your session…</div>
|
|
</div>
|
|
</main>
|
|
|
|
<footer class="foot" v-cloak v-if="session">
|
|
<div class="container">
|
|
<span>Smart Photo Editor</span>
|
|
<span>Signed in as {{ session.phone }}</span>
|
|
</div>
|
|
</footer>
|
|
|
|
<script src="/assets/cropper/app.js"></script>
|
|
</div>
|
|
</body>
|
|
</html>
|