166 lines
5.1 KiB
JavaScript
166 lines
5.1 KiB
JavaScript
#!/usr/bin/env node
|
||
|
||
/**
|
||
* Миграционный скрипт для добавления arrowHint и accentedOption настроек
|
||
* к существующим trialChoice экранам.
|
||
*
|
||
* Этот скрипт:
|
||
* 1. Подключается к MongoDB
|
||
* 2. Находит все воронки с экранами template: "trialChoice"
|
||
* 3. Добавляет дефолтные arrowHint и accentedOption настройки если их нет
|
||
*
|
||
* Запуск:
|
||
* node scripts/migrate-trial-choice-arrow-hint.mjs
|
||
*
|
||
* Опции:
|
||
* --dry-run Показать изменения без записи в базу
|
||
*/
|
||
|
||
import mongoose from 'mongoose';
|
||
import dotenv from 'dotenv';
|
||
|
||
// Load environment variables
|
||
dotenv.config({ path: '.env.local' });
|
||
|
||
const MONGODB_URI = process.env.MONGODB_URI || 'mongodb://localhost:27017/witlab-funnel';
|
||
|
||
const isDryRun = process.argv.includes('--dry-run');
|
||
|
||
// Дефолтные значения для arrowHint
|
||
const DEFAULT_ARROW_HINT = {
|
||
text: "It costs us {{maxTrialPrice}} to compensate our team for the work involved in creating your personalized portrait and guide, but please choose the amount you are comfortable with.",
|
||
position: "bottom-right"
|
||
};
|
||
|
||
// Дефолтное значение для accentedOption
|
||
const DEFAULT_ACCENTED_OPTION = "server";
|
||
|
||
// Mongoose schema (minimal for migration)
|
||
const FunnelSchema = new mongoose.Schema({
|
||
funnelData: mongoose.Schema.Types.Mixed,
|
||
name: String,
|
||
status: String,
|
||
}, {
|
||
timestamps: true,
|
||
collection: 'funnels'
|
||
});
|
||
|
||
const FunnelModel = mongoose.models.Funnel || mongoose.model('Funnel', FunnelSchema);
|
||
|
||
async function connectToDatabase() {
|
||
try {
|
||
await mongoose.connect(MONGODB_URI, {
|
||
bufferCommands: false,
|
||
maxPoolSize: 10,
|
||
serverSelectionTimeoutMS: 5000,
|
||
socketTimeoutMS: 45000,
|
||
});
|
||
console.log('✅ Connected to MongoDB');
|
||
} catch (error) {
|
||
console.error('❌ Failed to connect to MongoDB:', error.message);
|
||
process.exit(1);
|
||
}
|
||
}
|
||
|
||
async function migrateFunnels() {
|
||
// Находим все воронки с trialChoice экранами без arrowHint
|
||
const funnels = await FunnelModel.find({
|
||
'funnelData.screens': {
|
||
$elemMatch: {
|
||
template: 'trialChoice'
|
||
}
|
||
}
|
||
});
|
||
|
||
console.log(`\n📋 Found ${funnels.length} funnels with trialChoice screens\n`);
|
||
|
||
let updatedCount = 0;
|
||
let screensUpdated = 0;
|
||
|
||
for (const funnel of funnels) {
|
||
const funnelId = funnel.funnelData?.meta?.id || funnel._id;
|
||
const funnelName = funnel.name || funnelId;
|
||
|
||
let hasChanges = false;
|
||
const screens = funnel.funnelData?.screens || [];
|
||
|
||
for (let i = 0; i < screens.length; i++) {
|
||
const screen = screens[i];
|
||
|
||
if (screen.template === 'trialChoice') {
|
||
const needsArrowHint = !screen.arrowHint;
|
||
const needsAccentedOption = screen.accentedOption === undefined;
|
||
|
||
if (needsArrowHint || needsAccentedOption) {
|
||
const updates = [];
|
||
if (needsArrowHint) updates.push('arrowHint');
|
||
if (needsAccentedOption) updates.push('accentedOption');
|
||
|
||
console.log(` 📍 [${funnelName}] Screen "${screen.id}" needs: ${updates.join(', ')}`);
|
||
|
||
if (!isDryRun) {
|
||
screens[i] = {
|
||
...screen,
|
||
...(needsArrowHint && { arrowHint: DEFAULT_ARROW_HINT }),
|
||
...(needsAccentedOption && { accentedOption: DEFAULT_ACCENTED_OPTION }),
|
||
};
|
||
}
|
||
|
||
hasChanges = true;
|
||
screensUpdated++;
|
||
} else {
|
||
console.log(` ✅ [${funnelName}] Screen "${screen.id}" already has all settings`);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (hasChanges) {
|
||
if (!isDryRun) {
|
||
funnel.funnelData.screens = screens;
|
||
funnel.markModified('funnelData');
|
||
await funnel.save();
|
||
console.log(` 💾 [${funnelName}] Saved changes`);
|
||
} else {
|
||
console.log(` 🔍 [${funnelName}] Would update (dry-run)`);
|
||
}
|
||
updatedCount++;
|
||
}
|
||
}
|
||
|
||
return { updatedCount, screensUpdated, total: funnels.length };
|
||
}
|
||
|
||
async function main() {
|
||
console.log('🚀 Starting trialChoice arrowHint migration...');
|
||
|
||
if (isDryRun) {
|
||
console.log('⚠️ DRY RUN MODE - No changes will be saved\n');
|
||
}
|
||
|
||
await connectToDatabase();
|
||
|
||
const { updatedCount, screensUpdated, total } = await migrateFunnels();
|
||
|
||
console.log('\n📊 Migration Summary:');
|
||
console.log('=====================');
|
||
console.log(`📁 Total funnels with trialChoice: ${total}`);
|
||
console.log(`📝 Funnels updated: ${updatedCount}`);
|
||
console.log(`🎯 Screens updated: ${screensUpdated}`);
|
||
|
||
if (isDryRun) {
|
||
console.log('\n⚠️ This was a dry run. Run without --dry-run to apply changes.');
|
||
} else if (updatedCount > 0) {
|
||
console.log('\n✅ Migration completed successfully!');
|
||
} else {
|
||
console.log('\n✨ All trialChoice screens already have arrowHint configured!');
|
||
}
|
||
|
||
await mongoose.connection.close();
|
||
console.log('\n👋 Database connection closed.');
|
||
}
|
||
|
||
main().catch(error => {
|
||
console.error('\n💥 Fatal error:', error);
|
||
process.exit(1);
|
||
});
|