Copy the Chatwoot (v4.14.0) frontend runnable subset into frontend/ for customization: - app/javascript/ (Vue SPA: dashboard, widget, sdk, portal, superadmin) - app/views/ (ERB templates for vite-plugin-ruby entrypoint resolution) - app/helpers/, app/assets/ (Rails view helpers, static assets) - enterprise/ (Enterprise edition frontend overlay) - config/vite.json, vite.config.ts, bin/vite (Vite-Rails toolchain) - package.json, pnpm-lock.yaml, tailwind/postcss/eslint configs - Gemfile, Gemfile.lock (vite_rails gem for bin/vite binstub) Excluded Rails backend: controllers, models, services, jobs, mailers, policies, db, lib, spec, public, node_modules. Update references to the new frontend location: - .gitignore: exclude frontend build artifacts (node_modules, tmp, packs), keep frontend/bin/ and frontend/vendor/ via negation - backend/scripts/parity_frontend_smoke.sh: CHATWOOT_DIR default reference/chatwoot -> ../frontend - backend/scripts/parity_frontend_browser_smoke.mjs: same default update - AGENTS.md: add frontend section with Rails/Vite coupling notes - README: architecture tree includes frontend/
93 lines
2.2 KiB
Vue
93 lines
2.2 KiB
Vue
<script>
|
|
import { required } from '@vuelidate/validators';
|
|
import { useVuelidate } from '@vuelidate/core';
|
|
import Modal from '../../Modal.vue';
|
|
|
|
import NextButton from 'dashboard/components-next/button/Button.vue';
|
|
|
|
export default {
|
|
components: {
|
|
Modal,
|
|
NextButton,
|
|
},
|
|
props: {
|
|
show: { type: Boolean, default: false },
|
|
title: { type: String, default: '' },
|
|
message: { type: String, default: '' },
|
|
confirmText: { type: String, default: '' },
|
|
rejectText: { type: String, default: '' },
|
|
confirmValue: { type: String, default: '' },
|
|
confirmPlaceHolderText: { type: String, default: '' },
|
|
},
|
|
emits: ['onClose', 'onConfirm', 'update:show'],
|
|
setup() {
|
|
return { v$: useVuelidate() };
|
|
},
|
|
data() {
|
|
return {
|
|
value: '',
|
|
};
|
|
},
|
|
validations: {
|
|
value: {
|
|
required,
|
|
isEqual(value) {
|
|
// Trim whitespace from both input and target values
|
|
const normalizedInput = (value || '').trim();
|
|
const normalizedTarget = (this.confirmValue || '').trim();
|
|
return normalizedInput === normalizedTarget;
|
|
},
|
|
},
|
|
},
|
|
computed: {
|
|
localShow: {
|
|
get() {
|
|
return this.show;
|
|
},
|
|
set(value) {
|
|
this.$emit('update:show', value);
|
|
},
|
|
},
|
|
},
|
|
methods: {
|
|
closeModal() {
|
|
this.value = '';
|
|
this.$emit('onClose');
|
|
},
|
|
onConfirm() {
|
|
this.$emit('onConfirm');
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<Modal v-model:show="localShow" :on-close="closeModal">
|
|
<woot-modal-header :header-title="title" :header-content="message" />
|
|
<form @submit.prevent="onConfirm">
|
|
<woot-input
|
|
v-model="value"
|
|
type="text"
|
|
:class="{ error: v$.value.$error }"
|
|
:placeholder="confirmPlaceHolderText"
|
|
@blur="v$.value.$touch"
|
|
/>
|
|
<div class="flex items-center justify-end gap-2">
|
|
<NextButton
|
|
faded
|
|
slate
|
|
type="reset"
|
|
:label="rejectText"
|
|
@click.prevent="closeModal"
|
|
/>
|
|
<NextButton
|
|
ruby
|
|
type="submit"
|
|
:label="confirmText"
|
|
:disabled="v$.value.$invalid"
|
|
/>
|
|
</div>
|
|
</form>
|
|
</Modal>
|
|
</template>
|