djs-builder 0.7.9 → 0.7.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -6
- package/function/dash.js +290 -39
- package/function/function.js +50 -39
- package/function/level.js +337 -10
- package/handler/starter.js +34 -5
- package/package.json +2 -2
- package/views/dashboard.ejs +52 -18
- package/views/levels.ejs +671 -32
- package/views/logs.ejs +48 -13
package/function/level.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const { Schema, model } = require("mongoose");
|
|
2
2
|
|
|
3
|
+
////////////////////////////////! � User Level Schema
|
|
3
4
|
const levelSchema = new Schema({
|
|
4
5
|
userId: String,
|
|
5
6
|
guildId: String,
|
|
@@ -7,15 +8,188 @@ const levelSchema = new Schema({
|
|
|
7
8
|
voice: { type: Number, default: 0 },
|
|
8
9
|
totalXP: { type: Number, default: 0 },
|
|
9
10
|
level: { type: Number, default: 0 },
|
|
11
|
+
lastMessageTimestamp: { type: Date, default: null },
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
////////////////////////////////! ⚙️ Leveling Sub-Schema
|
|
15
|
+
const levelingSchema = new Schema({
|
|
16
|
+
type: { type: String, default: "line" },
|
|
17
|
+
amount: { type: Number, default: 100 },
|
|
18
|
+
a: { type: Number, default: 5 },
|
|
19
|
+
b: { type: Number, default: 50 },
|
|
20
|
+
c: { type: Number, default: 100 },
|
|
21
|
+
customLevels: { type: Object, default: {} },
|
|
22
|
+
}, { _id: false });
|
|
23
|
+
|
|
24
|
+
////////////////////////////////! ⚙️ Guild Config Schema
|
|
25
|
+
const guildSchema = new Schema({
|
|
26
|
+
guildId: { type: String, required: true, unique: true },
|
|
27
|
+
initialized: { type: Boolean, default: false },
|
|
28
|
+
|
|
29
|
+
minXP: { type: Number, default: 5 },
|
|
30
|
+
maxXP: { type: Number, default: 12 },
|
|
31
|
+
xpMultiplier: { type: Number, default: 1 },
|
|
32
|
+
maxLevel: { type: Number, default: null },
|
|
33
|
+
cooldown: { type: Number, default: 0 },
|
|
34
|
+
roleReward: { type: Object, default: {} },
|
|
35
|
+
blacklistedChannels: { type: Array, default: [] },
|
|
36
|
+
disabled: { type: Boolean, default: false },
|
|
37
|
+
leveling: { type: levelingSchema, default: () => ({ type: "line", amount: 100, a: 5, b: 50, c: 100, customLevels: {} }) },
|
|
38
|
+
|
|
10
39
|
});
|
|
11
40
|
|
|
12
41
|
const Level = model("Level", levelSchema);
|
|
42
|
+
const levelGuild = model("levelGuild", guildSchema);
|
|
43
|
+
|
|
44
|
+
////////////////////////////////! 🗃️ Cache System
|
|
45
|
+
const configCache = new Map();
|
|
46
|
+
|
|
47
|
+
function clearConfigCache(guildId) {
|
|
48
|
+
if (guildId) {
|
|
49
|
+
configCache.delete(guildId);
|
|
50
|
+
} else {
|
|
51
|
+
configCache.clear();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async function getCachedConfig(guildId) {
|
|
56
|
+
if (configCache.has(guildId)) {
|
|
57
|
+
return configCache.get(guildId);
|
|
58
|
+
}
|
|
59
|
+
const config = await levelGuild.findOne({ guildId });
|
|
60
|
+
if (config) configCache.set(guildId, config);
|
|
61
|
+
return config;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
////////////////////////////////! 🧮 Calculate XP needed for level
|
|
65
|
+
function xpNeeded(level, config = {}) {
|
|
66
|
+
const leveling = config.leveling || { type: "line", amount: 100 };
|
|
67
|
+
const type = leveling.type || "line";
|
|
68
|
+
|
|
69
|
+
if (leveling.customLevels && leveling.customLevels[level]) {
|
|
70
|
+
return leveling.customLevels[level];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
switch (type) {
|
|
74
|
+
case "exponential":
|
|
75
|
+
return Math.floor(leveling.amount * Math.pow(2, level));
|
|
76
|
+
case "balanced":
|
|
77
|
+
const a = leveling.a || 5;
|
|
78
|
+
const b = leveling.b || 50;
|
|
79
|
+
const c = leveling.c || 100;
|
|
80
|
+
return Math.floor(a * Math.pow(level, 2) + b * level + c);
|
|
81
|
+
case "custom":
|
|
82
|
+
return leveling.customLevels?.[level] || level * 1000;
|
|
83
|
+
case "line":
|
|
84
|
+
default:
|
|
85
|
+
return (level + 1) * (leveling.amount || 100);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function calculateLevel(totalXP, config = {}) {
|
|
90
|
+
let level = 0;
|
|
91
|
+
const maxLevel = config.maxLevel || null;
|
|
92
|
+
|
|
93
|
+
while (totalXP >= xpNeeded(level, config)) {
|
|
94
|
+
level++;
|
|
95
|
+
if (maxLevel && level >= maxLevel) {
|
|
96
|
+
return maxLevel;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return level;
|
|
100
|
+
}
|
|
13
101
|
|
|
14
102
|
function randomXP(min, max) {
|
|
15
103
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
16
104
|
}
|
|
17
105
|
|
|
106
|
+
////////////////////////////////* 🎮 Main setLevel Function
|
|
107
|
+
|
|
108
|
+
async function setLevel(client, guilds, callbacks = {}) {
|
|
109
|
+
client.levelGuilds = new Set(guilds.map(g => g.id));
|
|
110
|
+
client.levelDashboardGuilds = new Set(guilds.filter(g => g.Dashboard === true).map(g => g.id));
|
|
111
|
+
|
|
112
|
+
for (const guild of guilds) {
|
|
113
|
+
const trueGuild = client.guilds.cache.get(guild.id);
|
|
114
|
+
if (!trueGuild) continue;
|
|
115
|
+
|
|
116
|
+
const existingConfig = await levelGuild.findOne({ guildId: guild.id });
|
|
117
|
+
|
|
118
|
+
const { id, Dashboard, ...guildConfig } = guild;
|
|
119
|
+
|
|
120
|
+
if (!existingConfig) {
|
|
121
|
+
const newConfig = new levelGuild({ guildId: id, initialized: true, ...guildConfig });
|
|
122
|
+
await newConfig.save();
|
|
123
|
+
configCache.set(id, newConfig);
|
|
124
|
+
} else {
|
|
125
|
+
if (guild.Dashboard) {
|
|
126
|
+
await levelGuild.findOneAndUpdate(
|
|
127
|
+
{ guildId: id },
|
|
128
|
+
{ initialized: true },
|
|
129
|
+
{ new: true }
|
|
130
|
+
);
|
|
131
|
+
} else {
|
|
132
|
+
await levelGuild.findOneAndDelete({ guildId: id });
|
|
133
|
+
const newConfig = new levelGuild({ guildId: id, initialized: true, ...guildConfig });
|
|
134
|
+
await newConfig.save();
|
|
135
|
+
}
|
|
136
|
+
clearConfigCache(id);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
client.on("messageCreate", async (msg) => {
|
|
141
|
+
if (msg.author.bot || !msg.guild) return;
|
|
142
|
+
|
|
143
|
+
// ✅ Check if guild is in active level system
|
|
144
|
+
if (!client.levelGuilds || !client.levelGuilds.has(msg.guild.id)) return;
|
|
145
|
+
|
|
146
|
+
const guildConfig = await getCachedConfig(msg.guild.id);
|
|
147
|
+
if (!guildConfig) return;
|
|
148
|
+
|
|
149
|
+
const guildOptions = guilds.find(g => g.id === msg.guild.id) || {};
|
|
150
|
+
|
|
151
|
+
const result = await addXP(msg.author.id, msg.guild.id, {
|
|
152
|
+
...guildOptions,
|
|
153
|
+
channelId: msg.channel.id,
|
|
154
|
+
member: msg.member,
|
|
155
|
+
xpType: "text",
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
if (result.disabled || result.blacklisted || result.onCooldown) return;
|
|
159
|
+
|
|
160
|
+
if (callbacks.onXP) {
|
|
161
|
+
try { await callbacks.onXP(msg, result); } catch (e) { console.error("setLevel onXP error:", e); }
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (result.leveledUp && callbacks.onLevelUp) {
|
|
165
|
+
try { await callbacks.onLevelUp(msg, result); } catch (e) { console.error("setLevel onLevelUp error:", e); }
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (result.newRole?.length > 0 && callbacks.onRoleReward) {
|
|
169
|
+
for (const role of result.newRole) {
|
|
170
|
+
try { await callbacks.onRoleReward(msg, result, role); } catch (e) { console.error("setLevel onRoleReward error:", e); }
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
////////////////////////////////! 🎮 Main addXP Function
|
|
179
|
+
|
|
180
|
+
|
|
18
181
|
async function addXP(userId, guildId, options = {}) {
|
|
182
|
+
////////////////////////////////! 🗃️ Get config from Dashboard or options
|
|
183
|
+
let config = options.Dashboard
|
|
184
|
+
? await getCachedConfig(guildId) || {}
|
|
185
|
+
: options;
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
////////////////////////////////! ❌ Check if disabled
|
|
189
|
+
if (config.disabled) {
|
|
190
|
+
return { disabled: true, newLevel: 0, oldLevel: 0, totalXP: 0, leveledUp: false };
|
|
191
|
+
}
|
|
192
|
+
|
|
19
193
|
let data = await Level.findOne({ userId, guildId });
|
|
20
194
|
if (!data) {
|
|
21
195
|
data = new Level({ userId, guildId });
|
|
@@ -23,12 +197,50 @@ async function addXP(userId, guildId, options = {}) {
|
|
|
23
197
|
|
|
24
198
|
const oldLevel = data.level || 0;
|
|
25
199
|
let leveledUp = false;
|
|
200
|
+
let roleRewardAdded = false;
|
|
201
|
+
let newRole = [];
|
|
202
|
+
|
|
203
|
+
////////////////////////////////! 🚫 Blacklist check
|
|
204
|
+
if (options.channelId && config.blacklistedChannels?.includes(options.channelId)) {
|
|
205
|
+
return {
|
|
206
|
+
newLevel: data.level,
|
|
207
|
+
oldLevel,
|
|
208
|
+
totalXP: data.totalXP,
|
|
209
|
+
leveledUp: false,
|
|
210
|
+
blacklisted: true,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
////////////////////////////////! ⏱️ Cooldown check
|
|
216
|
+
const cooldownDuration = config.cooldown ?? options.cooldown ?? 0;
|
|
217
|
+
|
|
218
|
+
if (cooldownDuration > 0) {
|
|
219
|
+
const now = new Date();
|
|
220
|
+
if (data.lastMessageTimestamp) {
|
|
221
|
+
const timeDiff = (now - data.lastMessageTimestamp) / 1000;
|
|
222
|
+
if (timeDiff < cooldownDuration) {
|
|
223
|
+
return {
|
|
224
|
+
newLevel: data.level,
|
|
225
|
+
oldLevel,
|
|
226
|
+
totalXP: data.totalXP,
|
|
227
|
+
leveledUp: false,
|
|
228
|
+
onCooldown: true,
|
|
229
|
+
remainingCooldown: Math.ceil(cooldownDuration - timeDiff),
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
data.lastMessageTimestamp = now;
|
|
234
|
+
}
|
|
26
235
|
|
|
27
236
|
////////////////////////////////! 🎲 XP
|
|
28
|
-
|
|
29
|
-
options.amount_add ??
|
|
237
|
+
let xpToAdd =
|
|
238
|
+
options.amount_add ??
|
|
239
|
+
randomXP(config.minXP || 5, config.maxXP || 12);
|
|
240
|
+
|
|
241
|
+
xpToAdd = Math.floor(xpToAdd * (config.xpMultiplier || 1));
|
|
30
242
|
|
|
31
|
-
data[options.
|
|
243
|
+
data[options.xpType || "text"] += xpToAdd;
|
|
32
244
|
data.totalXP += xpToAdd;
|
|
33
245
|
|
|
34
246
|
////////////////////////////////! 🎯 Level boost
|
|
@@ -37,24 +249,70 @@ async function addXP(userId, guildId, options = {}) {
|
|
|
37
249
|
leveledUp = true;
|
|
38
250
|
}
|
|
39
251
|
|
|
40
|
-
////////////////////////////////!
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
252
|
+
////////////////////////////////! 🔋 xp boost
|
|
253
|
+
if (options.totalXP_add) {
|
|
254
|
+
data.totalXP += options.totalXP_add;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (options.text_add) {
|
|
258
|
+
data.text += options.text_add;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (options.voice_add) {
|
|
262
|
+
data.voice += options.voice_add;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
////////////////////////////////! ✅ Calculate correct level
|
|
266
|
+
const newCalculatedLevel = calculateLevel(data.totalXP, config);
|
|
267
|
+
|
|
268
|
+
if (newCalculatedLevel > data.level) {
|
|
269
|
+
if (config.roleReward) {
|
|
270
|
+
const rewardLevels = Object.keys(config.roleReward)
|
|
271
|
+
.map(Number)
|
|
272
|
+
.filter(lvl => lvl === newCalculatedLevel)
|
|
273
|
+
.sort((a, b) => b - a);
|
|
274
|
+
|
|
275
|
+
if (rewardLevels.length > 0) {
|
|
276
|
+
const highestRewardLevel = rewardLevels[0];
|
|
277
|
+
newRole.push({
|
|
278
|
+
level: highestRewardLevel,
|
|
279
|
+
roleId: config.roleReward[highestRewardLevel]
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
data.level = newCalculatedLevel;
|
|
44
284
|
leveledUp = true;
|
|
45
285
|
}
|
|
46
286
|
|
|
47
287
|
await data.save();
|
|
48
288
|
|
|
289
|
+
////////////////////////////////! 🎖️ Auto add roles
|
|
290
|
+
if (options.member && newRole.length > 0) {
|
|
291
|
+
for (const role of newRole) {
|
|
292
|
+
try {
|
|
293
|
+
await options.member.roles.add(role.roleId);
|
|
294
|
+
roleRewardAdded = true;
|
|
295
|
+
} catch (err) {
|
|
296
|
+
roleRewardAdded = "Failed to add role: " + err.message;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
49
301
|
return {
|
|
50
302
|
newLevel: data.level,
|
|
51
303
|
oldLevel,
|
|
52
304
|
totalXP: data.totalXP,
|
|
53
305
|
leveledUp,
|
|
306
|
+
xpAdded: xpToAdd,
|
|
307
|
+
xpForNextLevel: xpNeeded(data.level, config),
|
|
308
|
+
remainingXP: xpNeeded(data.level, config) - data.totalXP,
|
|
309
|
+
roleRewardAdded,
|
|
310
|
+
newRole,
|
|
311
|
+
multiplierUsed: config.xpMultiplier || 1,
|
|
54
312
|
};
|
|
55
313
|
}
|
|
56
314
|
|
|
57
|
-
////////////////////////////////!
|
|
315
|
+
////////////////////////////////! 🧑🤝🧑 User data
|
|
58
316
|
async function UserLevel(userId, guildId) {
|
|
59
317
|
return (
|
|
60
318
|
(await Level.findOne({ userId, guildId })) || {
|
|
@@ -66,11 +324,80 @@ async function UserLevel(userId, guildId) {
|
|
|
66
324
|
);
|
|
67
325
|
}
|
|
68
326
|
|
|
69
|
-
////////////////////////////////! 🏆
|
|
327
|
+
////////////////////////////////! 🏆 Leaderboard
|
|
70
328
|
async function leaderboard(guildId, type = "totalXP", limit = 10) {
|
|
71
329
|
return await Level.find({ guildId })
|
|
72
330
|
.sort({ [type]: -1 })
|
|
73
331
|
.limit(limit);
|
|
74
332
|
}
|
|
75
333
|
|
|
76
|
-
|
|
334
|
+
////////////////////////////////! 🏅 Get user rank
|
|
335
|
+
async function getUserRank(userId, guildId, type = "totalXP") {
|
|
336
|
+
const allUsers = await Level.find({ guildId }).sort({ [type]: -1 });
|
|
337
|
+
const rank = allUsers.findIndex(u => u.userId === userId) + 1;
|
|
338
|
+
return rank || null;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
////////////////////////////////! 🗑️ Delete user data
|
|
343
|
+
async function resetUser(userId, guildId) {
|
|
344
|
+
return await Level.findOneAndDelete({ userId, guildId });
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
////////////////////////////////! 🔥 Reset all users in a guild
|
|
348
|
+
async function resetGuild(guildId) {
|
|
349
|
+
return await Level.deleteMany({ guildId });
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
////////////////////////////////! 📋 Get level info
|
|
353
|
+
function getLevelInfo(level, config = {}) {
|
|
354
|
+
return {
|
|
355
|
+
level,
|
|
356
|
+
xpNeeded: xpNeeded(level, config),
|
|
357
|
+
xpForNext: xpNeeded(level + 1, config),
|
|
358
|
+
xpDifference: xpNeeded(level + 1, config) - xpNeeded(level, config),
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
////////////////////////////////! ⚙️ Get Guild Config
|
|
363
|
+
async function getGuildConfig(guildId) {
|
|
364
|
+
return await getCachedConfig(guildId);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
////////////////////////////////! ✏️ Update Guild Config
|
|
368
|
+
async function updateGuildConfig(guildId, updates) {
|
|
369
|
+
const result = await levelGuild.findOneAndUpdate(
|
|
370
|
+
{ guildId },
|
|
371
|
+
{ guildId, ...updates },
|
|
372
|
+
{ upsert: true, new: true }
|
|
373
|
+
);
|
|
374
|
+
|
|
375
|
+
clearConfigCache(guildId);
|
|
376
|
+
return result;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
////////////////////////////////! 🗑️ Delete Guild Config
|
|
380
|
+
async function deleteGuildConfig(guildId) {
|
|
381
|
+
const result = await levelGuild.findOneAndDelete({ guildId });
|
|
382
|
+
clearConfigCache(guildId);
|
|
383
|
+
return result;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
module.exports = {
|
|
387
|
+
Level,
|
|
388
|
+
levelGuild,
|
|
389
|
+
addXP,
|
|
390
|
+
UserLevel,
|
|
391
|
+
leaderboard,
|
|
392
|
+
getUserRank,
|
|
393
|
+
resetUser,
|
|
394
|
+
resetGuild,
|
|
395
|
+
xpNeeded,
|
|
396
|
+
calculateLevel,
|
|
397
|
+
getLevelInfo,
|
|
398
|
+
getGuildConfig,
|
|
399
|
+
updateGuildConfig,
|
|
400
|
+
deleteGuildConfig,
|
|
401
|
+
clearConfigCache,
|
|
402
|
+
setLevel
|
|
403
|
+
};
|
package/handler/starter.js
CHANGED
|
@@ -514,7 +514,24 @@ async function starter(client, options) {
|
|
|
514
514
|
}
|
|
515
515
|
|
|
516
516
|
const { Wait, CreateBar, CreateRow, GetUser , CreateModal, CreateComponents } = require("../function/function");
|
|
517
|
-
const {
|
|
517
|
+
const {
|
|
518
|
+
Level,
|
|
519
|
+
levelGuild,
|
|
520
|
+
addXP,
|
|
521
|
+
UserLevel,
|
|
522
|
+
leaderboard,
|
|
523
|
+
getUserRank,
|
|
524
|
+
resetUser,
|
|
525
|
+
resetGuild,
|
|
526
|
+
xpNeeded,
|
|
527
|
+
calculateLevel,
|
|
528
|
+
getLevelInfo,
|
|
529
|
+
getGuildConfig,
|
|
530
|
+
updateGuildConfig,
|
|
531
|
+
deleteGuildConfig,
|
|
532
|
+
clearConfigCache,
|
|
533
|
+
setLevel
|
|
534
|
+
} = require("../function/level");
|
|
518
535
|
const { log , Log , getLogConfigData} = require("../function/log");
|
|
519
536
|
const { dashboard } = require("../function/dash");
|
|
520
537
|
|
|
@@ -542,7 +559,22 @@ const {
|
|
|
542
559
|
} = require("../function/giveaway");
|
|
543
560
|
|
|
544
561
|
module.exports = {
|
|
545
|
-
Level,
|
|
562
|
+
Level,
|
|
563
|
+
levelGuild,
|
|
564
|
+
addXP,
|
|
565
|
+
UserLevel,
|
|
566
|
+
leaderboard,
|
|
567
|
+
getUserRank,
|
|
568
|
+
resetUser,
|
|
569
|
+
resetGuild,
|
|
570
|
+
xpNeeded,
|
|
571
|
+
calculateLevel,
|
|
572
|
+
getLevelInfo,
|
|
573
|
+
getGuildConfig,
|
|
574
|
+
updateGuildConfig,
|
|
575
|
+
deleteGuildConfig,
|
|
576
|
+
clearConfigCache,
|
|
577
|
+
setLevel,
|
|
546
578
|
giveaway,
|
|
547
579
|
starter,
|
|
548
580
|
dashboard,
|
|
@@ -556,9 +588,6 @@ module.exports = {
|
|
|
556
588
|
CreateModal,
|
|
557
589
|
CreateComponents,
|
|
558
590
|
GetUser,
|
|
559
|
-
addXP,
|
|
560
|
-
UserLevel,
|
|
561
|
-
leaderboard,
|
|
562
591
|
Gstart,
|
|
563
592
|
Gcheck,
|
|
564
593
|
Greroll,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "djs-builder",
|
|
3
|
-
"version": "0.7.
|
|
4
|
-
"note": "🎉 Package Update v0.7.
|
|
3
|
+
"version": "0.7.10",
|
|
4
|
+
"note": "🎉 Package Update v0.7.10! \n\n- 🎮 NEW: setLevel Function!\n • All-in-one level system setup\n • Automatic message listener\n • Callbacks: onLevelUp, onRoleReward, onXP\n • Dashboard Mode & Code Mode support\n • Auto role rewards on level up\n • Voice XP support via addVoiceXP\n\n- 📊 Level System Improvements!\n • getGuildConfig with full output example\n • updateGuildConfig for programmatic changes\n • XP Calculation Types: line, exponential, balanced, custom\n • Cooldown & Blacklist support\n\n- 🌐 Dashboard System!\n • Discord OAuth2 Login\n • Server, Level, Giveaway & Blacklist Management\n • Logs Management Page\n\n- <:npm:1107014411375353968> Learn more on [NPM](https://www.npmjs.com/package/djs-builder)\n- <:Discord:906936109114753024> DISCORD SERVER : [LINK](https://discord.gg/uYcKCZk3)",
|
|
5
5
|
"description": "🎉 Full-featured Discord.js utilities: CreateComponents, CreateModal, Dashboard, Logging & more! 🥏",
|
|
6
6
|
"main": "handler/starter.js",
|
|
7
7
|
"dependencies": {
|
package/views/dashboard.ejs
CHANGED
|
@@ -725,6 +725,23 @@
|
|
|
725
725
|
</div>
|
|
726
726
|
</div>
|
|
727
727
|
|
|
728
|
+
<!-- Confirm Modal -->
|
|
729
|
+
<div class="modal" id="confirmModal">
|
|
730
|
+
<div class="modal-content" style="max-width: 400px;">
|
|
731
|
+
<div class="modal-header">
|
|
732
|
+
<h3 id="confirmTitle"><i class="ri-question-line" style="color: var(--warning);"></i> تأكيد</h3>
|
|
733
|
+
<button class="modal-close" onclick="closeConfirmModal()">×</button>
|
|
734
|
+
</div>
|
|
735
|
+
<div class="modal-body">
|
|
736
|
+
<p id="confirmMessage" style="font-size: 15px; text-align: center; padding: 10px 0;"></p>
|
|
737
|
+
</div>
|
|
738
|
+
<div class="modal-footer" style="justify-content: center;">
|
|
739
|
+
<button class="btn btn-secondary" onclick="closeConfirmModal()">إلغاء</button>
|
|
740
|
+
<button class="btn btn-primary" id="confirmBtn" style="background: var(--danger);"><i class="ri-check-line"></i> تأكيد</button>
|
|
741
|
+
</div>
|
|
742
|
+
</div>
|
|
743
|
+
</div>
|
|
744
|
+
|
|
728
745
|
<div class="toast" id="toast"><i class="ri-checkbox-circle-fill"></i><span id="toastText"></span></div>
|
|
729
746
|
|
|
730
747
|
<script>
|
|
@@ -766,6 +783,23 @@
|
|
|
766
783
|
setTimeout(() => toast.classList.remove('show'), 3000);
|
|
767
784
|
}
|
|
768
785
|
|
|
786
|
+
// Confirm Modal Functions
|
|
787
|
+
let confirmCallback = null;
|
|
788
|
+
function showConfirm(message, callback, title = 'تأكيد') {
|
|
789
|
+
document.getElementById('confirmMessage').textContent = message;
|
|
790
|
+
document.getElementById('confirmTitle').innerHTML = '<i class="ri-question-line" style="color: var(--warning);"></i> ' + title;
|
|
791
|
+
confirmCallback = callback;
|
|
792
|
+
document.getElementById('confirmModal').classList.add('show');
|
|
793
|
+
}
|
|
794
|
+
function closeConfirmModal() {
|
|
795
|
+
document.getElementById('confirmModal').classList.remove('show');
|
|
796
|
+
confirmCallback = null;
|
|
797
|
+
}
|
|
798
|
+
document.getElementById('confirmBtn').addEventListener('click', function() {
|
|
799
|
+
if (confirmCallback) confirmCallback();
|
|
800
|
+
closeConfirmModal();
|
|
801
|
+
});
|
|
802
|
+
|
|
769
803
|
// Modal functions
|
|
770
804
|
function selectBlType(type) {
|
|
771
805
|
document.querySelectorAll('.type-btn').forEach(btn => {
|
|
@@ -867,24 +901,24 @@
|
|
|
867
901
|
} catch (e) { showToast('حدث خطأ', 'error'); }
|
|
868
902
|
}
|
|
869
903
|
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
}
|
|
887
|
-
}
|
|
904
|
+
function removeFromGlobalBlacklist(type, id) {
|
|
905
|
+
showConfirm('هل أنت متأكد من الإزالة؟', async () => {
|
|
906
|
+
try {
|
|
907
|
+
const res = await fetch('/api/blacklist', {
|
|
908
|
+
method: 'DELETE',
|
|
909
|
+
headers: { 'Content-Type': 'application/json' },
|
|
910
|
+
body: JSON.stringify({ type, id })
|
|
911
|
+
});
|
|
912
|
+
const data = await res.json();
|
|
913
|
+
|
|
914
|
+
if (data.success) {
|
|
915
|
+
showToast('تمت الإزالة بنجاح');
|
|
916
|
+
document.querySelector(`.bl-item[data-id="${id}"]`).remove();
|
|
917
|
+
} else {
|
|
918
|
+
showToast(data.error || 'خطأ', 'error');
|
|
919
|
+
}
|
|
920
|
+
} catch (e) { showToast('خطأ', 'error'); }
|
|
921
|
+
}, 'إزالة');
|
|
888
922
|
}
|
|
889
923
|
|
|
890
924
|
// Load blacklist on init
|