nodebb-plugin-niki-loyalty 1.0.26 → 1.0.29
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/library.js +266 -187
- package/package.json +1 -1
package/library.js
CHANGED
|
@@ -3,214 +3,293 @@
|
|
|
3
3
|
const db = require.main.require('./src/database');
|
|
4
4
|
const user = require.main.require('./src/user');
|
|
5
5
|
const routeHelpers = require.main.require('./src/controllers/helpers');
|
|
6
|
+
const nconf = require.main.require('nconf');
|
|
6
7
|
|
|
7
8
|
const Plugin = {};
|
|
8
9
|
|
|
9
|
-
//
|
|
10
|
+
// =========================
|
|
11
|
+
// SETTINGS & REWARDS
|
|
12
|
+
// =========================
|
|
13
|
+
const SETTINGS = {
|
|
14
|
+
pointsPerHeartbeat: 5,
|
|
15
|
+
dailyCap: 250,
|
|
16
|
+
// coffeeCost: 250, // (eski kodda vardı ama artık tier sistemi var; istersen kullanırız)
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// Rewards configuration (Ordered from highest cost to lowest)
|
|
10
20
|
const REWARDS = [
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
21
|
+
{ cost: 250, name: 'Ücretsiz Kahve ☕' },
|
|
22
|
+
{ cost: 180, name: '%60 İndirimli Kahve' },
|
|
23
|
+
{ cost: 120, name: '%30 İndirimli Kahve' },
|
|
24
|
+
{ cost: 60, name: '1 Kurabiye 🍪' },
|
|
15
25
|
];
|
|
16
26
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
dailyCap: 250
|
|
20
|
-
};
|
|
27
|
+
// TEST MODE (Set to true to bypass point checks)
|
|
28
|
+
const TEST_MODE_UNLIMITED = false;
|
|
21
29
|
|
|
22
|
-
//
|
|
23
|
-
|
|
30
|
+
// =========================
|
|
31
|
+
// HELPER FUNCTIONS
|
|
32
|
+
// =========================
|
|
33
|
+
function safeParseMaybeJson(x) {
|
|
34
|
+
if (x == null) return null;
|
|
35
|
+
if (typeof x === 'object') return x;
|
|
36
|
+
if (typeof x === 'string') {
|
|
24
37
|
try {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
38
|
+
return JSON.parse(x);
|
|
39
|
+
} catch (e) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function safeStringify(obj) {
|
|
47
|
+
try {
|
|
48
|
+
return JSON.stringify(obj);
|
|
49
|
+
} catch (e) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// =========================
|
|
55
|
+
// LOGGING
|
|
56
|
+
// =========================
|
|
57
|
+
async function addUserLog(uid, type, amount, desc) {
|
|
58
|
+
const logEntry = {
|
|
59
|
+
ts: Date.now(),
|
|
60
|
+
type, // 'earn' | 'spend'
|
|
61
|
+
amt: amount,
|
|
62
|
+
txt: desc,
|
|
63
|
+
};
|
|
64
|
+
const payload = safeStringify(logEntry);
|
|
65
|
+
if (!payload) return;
|
|
66
|
+
await db.listAppend(`niki:activity:${uid}`, payload);
|
|
67
|
+
await db.listTrim(`niki:activity:${uid}`, -50, -1);
|
|
29
68
|
}
|
|
30
69
|
|
|
31
70
|
async function addKasaLog(staffUid, customerName, customerUid, rewardName, amount) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
71
|
+
const logEntry = {
|
|
72
|
+
ts: Date.now(),
|
|
73
|
+
staff: staffUid,
|
|
74
|
+
cust: customerName,
|
|
75
|
+
cuid: customerUid,
|
|
76
|
+
amt: amount,
|
|
77
|
+
reward: rewardName, // Store the specific reward name
|
|
78
|
+
};
|
|
79
|
+
const payload = safeStringify(logEntry);
|
|
80
|
+
if (!payload) return;
|
|
81
|
+
await db.listAppend('niki:kasa:history', payload);
|
|
82
|
+
await db.listTrim('niki:kasa:history', -100, -1);
|
|
44
83
|
}
|
|
45
84
|
|
|
85
|
+
// =========================
|
|
86
|
+
// PLUGIN INIT
|
|
87
|
+
// =========================
|
|
46
88
|
Plugin.init = async function (params) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
89
|
+
const router = params.router;
|
|
90
|
+
const middleware = params.middleware;
|
|
91
|
+
|
|
92
|
+
// 1) HEARTBEAT (Earn Points) + ✅ EARN LOG (2. koddaki özellik)
|
|
93
|
+
router.post('/api/niki-loyalty/heartbeat', middleware.ensureLoggedIn, async (req, res) => {
|
|
94
|
+
try {
|
|
95
|
+
const uid = req.uid;
|
|
96
|
+
const today = new Date().toISOString().slice(0, 10).replace(/-/g, '');
|
|
97
|
+
const dailyKey = `niki:daily:${uid}:${today}`;
|
|
98
|
+
|
|
99
|
+
const currentDailyScore = parseInt((await db.getObjectField(dailyKey, 'score')) || 0, 10);
|
|
100
|
+
|
|
101
|
+
if (currentDailyScore >= SETTINGS.dailyCap) {
|
|
102
|
+
return res.json({ earned: false, reason: 'daily_cap' });
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
await user.incrementUserFieldBy(uid, 'niki_points', SETTINGS.pointsPerHeartbeat);
|
|
106
|
+
await db.incrObjectFieldBy(dailyKey, 'score', SETTINGS.pointsPerHeartbeat);
|
|
107
|
+
|
|
108
|
+
// ✅ Log: Cüzdan geçmişinde "kazanım" görünsün
|
|
109
|
+
await addUserLog(uid, 'earn', SETTINGS.pointsPerHeartbeat, 'Ders Çalışma 📚');
|
|
110
|
+
|
|
111
|
+
const newBalance = await user.getUserField(uid, 'niki_points');
|
|
112
|
+
return res.json({ earned: true, points: SETTINGS.pointsPerHeartbeat, total: newBalance });
|
|
113
|
+
} catch (err) {
|
|
114
|
+
return res.status(500).json({ earned: false, reason: 'server_error' });
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// 2) WALLET DATA (Data + History + Rewards Info)
|
|
119
|
+
router.get('/api/niki-loyalty/wallet-data', middleware.ensureLoggedIn, async (req, res) => {
|
|
120
|
+
try {
|
|
121
|
+
const uid = req.uid;
|
|
122
|
+
const today = new Date().toISOString().slice(0, 10).replace(/-/g, '');
|
|
123
|
+
|
|
124
|
+
const [userData, dailyData, historyRaw] = await Promise.all([
|
|
125
|
+
user.getUserFields(uid, ['niki_points']),
|
|
126
|
+
db.getObject(`niki:daily:${uid}:${today}`),
|
|
127
|
+
db.getListRange(`niki:activity:${uid}`, 0, -1),
|
|
128
|
+
]);
|
|
129
|
+
|
|
130
|
+
const currentPoints = parseInt(userData?.niki_points || 0, 10);
|
|
131
|
+
const dailyScore = parseInt(dailyData?.score || 0, 10);
|
|
132
|
+
|
|
133
|
+
let dailyPercent = (dailyScore / SETTINGS.dailyCap) * 100;
|
|
134
|
+
if (dailyPercent > 100) dailyPercent = 100;
|
|
135
|
+
|
|
136
|
+
const history = (historyRaw || []).map(safeParseMaybeJson).filter(Boolean).reverse();
|
|
137
|
+
|
|
138
|
+
return res.json({
|
|
139
|
+
points: currentPoints,
|
|
140
|
+
dailyScore,
|
|
141
|
+
dailyCap: SETTINGS.dailyCap,
|
|
142
|
+
dailyPercent,
|
|
143
|
+
history,
|
|
144
|
+
rewards: REWARDS,
|
|
145
|
+
});
|
|
146
|
+
} catch (err) {
|
|
147
|
+
return res.status(500).json({ points: 0, history: [] });
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// 3) KASA HISTORY (+ ✅ iconBg + reward fallback (2. koddaki özellik))
|
|
152
|
+
router.get('/api/niki-loyalty/kasa-history', middleware.ensureLoggedIn, async (req, res) => {
|
|
153
|
+
try {
|
|
154
|
+
const isAdmin = await user.isAdministrator(req.uid);
|
|
155
|
+
const isMod = await user.isGlobalModerator(req.uid);
|
|
156
|
+
if (!isAdmin && !isMod) return res.status(403).json([]);
|
|
157
|
+
|
|
158
|
+
const raw = await db.getListRange('niki:kasa:history', 0, -1);
|
|
159
|
+
const rows = (raw || []).map(safeParseMaybeJson).filter(Boolean).reverse();
|
|
160
|
+
|
|
161
|
+
const uids = rows.map(r => parseInt(r.cuid, 10)).filter(n => Number.isFinite(n) && n > 0);
|
|
162
|
+
const users = await user.getUsersFields(uids, ['uid', 'username', 'userslug', 'picture', 'icon:bgColor']);
|
|
163
|
+
const userMap = {};
|
|
164
|
+
(users || []).forEach(u => {
|
|
165
|
+
userMap[u.uid] = u;
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
const rp = nconf.get('relative_path') || '';
|
|
169
|
+
|
|
170
|
+
const enriched = rows.map(r => {
|
|
171
|
+
const uid = parseInt(r.cuid, 10);
|
|
172
|
+
const u = userMap[uid];
|
|
173
|
+
if (!u) {
|
|
174
|
+
// yine de reward fallback yapalım
|
|
175
|
+
return { ...r, reward: r.reward || 'İşlem' };
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
...r,
|
|
179
|
+
cust: u.username || r.cust || 'Bilinmeyen',
|
|
180
|
+
userslug: u.userslug || r.userslug || '',
|
|
181
|
+
picture: u.picture || r.picture || '',
|
|
182
|
+
iconBg: u['icon:bgColor'] || r.iconBg || '#4b5563',
|
|
183
|
+
profileUrl: u.userslug ? `${rp}/user/${u.userslug}` : '',
|
|
184
|
+
reward: r.reward || 'İşlem',
|
|
185
|
+
};
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
return res.json(enriched);
|
|
189
|
+
} catch (err) {
|
|
190
|
+
return res.status(500).json([]);
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// 4) GENERATE QR (Check if user has enough for MINIMUM reward)
|
|
195
|
+
router.post('/api/niki-loyalty/generate-qr', middleware.ensureLoggedIn, async (req, res) => {
|
|
196
|
+
try {
|
|
197
|
+
const uid = req.uid;
|
|
198
|
+
const points = parseInt((await user.getUserField(uid, 'niki_points')) || 0, 10);
|
|
199
|
+
|
|
200
|
+
const minCost = REWARDS[REWARDS.length - 1].cost;
|
|
201
|
+
|
|
202
|
+
if (!TEST_MODE_UNLIMITED && points < minCost) {
|
|
203
|
+
return res.json({ success: false, message: `En az ${minCost} puan gerekli.` });
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const token = Math.random().toString(36).substring(2) + Date.now().toString(36);
|
|
207
|
+
await db.set(`niki:qr:${token}`, uid);
|
|
208
|
+
await db.expire(`niki:qr:${token}`, 120);
|
|
209
|
+
|
|
210
|
+
return res.json({ success: true, token });
|
|
211
|
+
} catch (err) {
|
|
212
|
+
return res.status(500).json({ success: false, message: 'Sunucu hatası' });
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// 5) SCAN QR (Determine Reward & Deduct Points)
|
|
217
|
+
router.post('/api/niki-loyalty/scan-qr', middleware.ensureLoggedIn, async (req, res) => {
|
|
218
|
+
try {
|
|
219
|
+
const token = req.body && req.body.token ? String(req.body.token) : '';
|
|
220
|
+
const isAdmin = await user.isAdministrator(req.uid);
|
|
221
|
+
const isMod = await user.isGlobalModerator(req.uid);
|
|
222
|
+
if (!isAdmin && !isMod) return res.status(403).json({ success: false, message: 'Yetkisiz' });
|
|
223
|
+
|
|
224
|
+
const customerUid = await db.get(`niki:qr:${token}`);
|
|
225
|
+
if (!customerUid) return res.json({ success: false, message: 'Geçersiz Kod' });
|
|
226
|
+
|
|
227
|
+
const pts = parseInt((await user.getUserField(customerUid, 'niki_points')) || 0, 10);
|
|
228
|
+
|
|
229
|
+
// Calculate best possible reward
|
|
230
|
+
let selectedReward = null;
|
|
231
|
+
if (!TEST_MODE_UNLIMITED) {
|
|
232
|
+
for (const reward of REWARDS) {
|
|
233
|
+
if (pts >= reward.cost) {
|
|
234
|
+
selectedReward = reward;
|
|
235
|
+
break;
|
|
236
|
+
}
|
|
105
237
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
// 3. KASA GEÇMİŞİ
|
|
109
|
-
router.get('/api/niki-loyalty/kasa-history', middleware.ensureLoggedIn, async (req, res) => {
|
|
110
|
-
try {
|
|
111
|
-
const isAdmin = await user.isAdministrator(req.uid);
|
|
112
|
-
const isMod = await user.isGlobalModerator(req.uid);
|
|
113
|
-
if (!isAdmin && !isMod) return res.status(403).json([]);
|
|
114
|
-
|
|
115
|
-
const rawHistory = await db.getListRange('niki:kasa:history', 0, -1);
|
|
116
|
-
const enrichedHistory = await Promise.all((rawHistory || []).reverse().map(async (item) => {
|
|
117
|
-
try {
|
|
118
|
-
if (typeof item === 'string') { try { item = JSON.parse(item); } catch (e) { return null; } }
|
|
119
|
-
if (!item || !item.cuid) return null;
|
|
120
|
-
const uData = await user.getUserFields(item.cuid, ['picture']);
|
|
121
|
-
item.picture = uData ? uData.picture : null;
|
|
122
|
-
return item;
|
|
123
|
-
} catch (err) { return null; }
|
|
124
|
-
}));
|
|
125
|
-
res.json(enrichedHistory.filter(i => i !== null));
|
|
126
|
-
} catch (e) { res.json([]); }
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
// 4. QR OLUŞTUR (En düşük ödül seviyesi kadar puanı var mı?)
|
|
130
|
-
router.post('/api/niki-loyalty/generate-qr', middleware.ensureLoggedIn, async (req, res) => {
|
|
131
|
-
try {
|
|
132
|
-
const uid = req.uid;
|
|
133
|
-
const points = parseInt(await user.getUserField(uid, 'niki_points')) || 0;
|
|
134
|
-
|
|
135
|
-
// En ucuz ödül (60 puan) kadar bile puanı yoksa izin verme
|
|
136
|
-
const minCost = REWARDS[REWARDS.length - 1].cost;
|
|
137
|
-
if (points < minCost) return res.json({ success: false, message: `En az ${minCost} puan gerekli.` });
|
|
138
|
-
|
|
139
|
-
const token = Math.random().toString(36).substring(2) + Date.now().toString(36);
|
|
140
|
-
await db.set(`niki:qr:${token}`, uid);
|
|
141
|
-
await db.expire(`niki:qr:${token}`, 120);
|
|
142
|
-
|
|
143
|
-
return res.json({ success: true, token: token });
|
|
144
|
-
} catch (e) { return res.json({ success: false, message: "Hata" }); }
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
// 5. QR OKUT (OTOMATİK ÖDÜL SEÇİMİ)
|
|
148
|
-
router.post('/api/niki-loyalty/scan-qr', middleware.ensureLoggedIn, async (req, res) => {
|
|
149
|
-
try {
|
|
150
|
-
const { token } = req.body;
|
|
151
|
-
const isAdmin = await user.isAdministrator(req.uid);
|
|
152
|
-
const isMod = await user.isGlobalModerator(req.uid);
|
|
153
|
-
if (!isAdmin && !isMod) return res.status(403).json({ success: false, message: 'Yetkisiz' });
|
|
154
|
-
|
|
155
|
-
const customerUid = await db.get(`niki:qr:${token}`);
|
|
156
|
-
if (!customerUid) return res.json({ success: false, message: 'Geçersiz Kod' });
|
|
157
|
-
|
|
158
|
-
const pts = parseInt(await user.getUserField(customerUid, 'niki_points')) || 0;
|
|
159
|
-
|
|
160
|
-
// --- HANGİ ÖDÜLÜ ALABİLİR? ---
|
|
161
|
-
let selectedReward = null;
|
|
162
|
-
|
|
163
|
-
// Ödülleri pahalıdan ucuza tara, ilk yeteni seç
|
|
164
|
-
for (const reward of REWARDS) {
|
|
165
|
-
if (pts >= reward.cost) {
|
|
166
|
-
selectedReward = reward;
|
|
167
|
-
break; // En büyüğü bulduk, döngüden çık
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
if (!selectedReward) {
|
|
172
|
-
return res.json({ success: false, message: 'Puan Yetersiz (Min: 60)' });
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// İŞLEM
|
|
176
|
-
await user.decrementUserFieldBy(customerUid, 'niki_points', selectedReward.cost);
|
|
177
|
-
await db.delete(`niki:qr:${token}`);
|
|
178
|
-
|
|
179
|
-
// LOGLAR
|
|
180
|
-
const customerData = await user.getUserFields(customerUid, ['username', 'picture']);
|
|
181
|
-
|
|
182
|
-
await addUserLog(customerUid, 'spend', selectedReward.cost, selectedReward.name);
|
|
183
|
-
await addKasaLog(req.uid, customerData.username, customerUid, selectedReward.name, selectedReward.cost);
|
|
184
|
-
|
|
185
|
-
// Frontend'e hangi ödülün verildiğini söyle
|
|
186
|
-
return res.json({
|
|
187
|
-
success: true,
|
|
188
|
-
customer: customerData,
|
|
189
|
-
rewardName: selectedReward.name,
|
|
190
|
-
cost: selectedReward.cost
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
} catch (e) {
|
|
194
|
-
return res.json({ success: false, message: "İşlem Hatası" });
|
|
238
|
+
if (!selectedReward) {
|
|
239
|
+
return res.json({ success: false, message: 'Puan Yetersiz' });
|
|
195
240
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
241
|
+
} else {
|
|
242
|
+
selectedReward = REWARDS[0];
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Deduct Points
|
|
246
|
+
if (!TEST_MODE_UNLIMITED) {
|
|
247
|
+
await user.decrementUserFieldBy(customerUid, 'niki_points', selectedReward.cost);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
await db.delete(`niki:qr:${token}`);
|
|
251
|
+
|
|
252
|
+
const customerData = await user.getUserFields(customerUid, ['username', 'picture', 'userslug']);
|
|
253
|
+
|
|
254
|
+
// Logs
|
|
255
|
+
await addUserLog(customerUid, 'spend', selectedReward.cost, selectedReward.name);
|
|
256
|
+
await addKasaLog(req.uid, customerData?.username || 'Bilinmeyen', customerUid, selectedReward.name, selectedReward.cost);
|
|
257
|
+
|
|
258
|
+
return res.json({
|
|
259
|
+
success: true,
|
|
260
|
+
customer: customerData,
|
|
261
|
+
rewardName: selectedReward.name,
|
|
262
|
+
cost: selectedReward.cost,
|
|
263
|
+
message: 'Onaylandı!',
|
|
264
|
+
});
|
|
265
|
+
} catch (err) {
|
|
266
|
+
return res.status(500).json({ success: false, message: 'Sunucu hatası' });
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// 6) PAGE ROUTES
|
|
271
|
+
routeHelpers.setupPageRoute(router, '/niki-kasa', middleware, [], async (req, res) => {
|
|
272
|
+
const isAdmin = await user.isAdministrator(req.uid);
|
|
273
|
+
const isMod = await user.isGlobalModerator(req.uid);
|
|
274
|
+
if (!isAdmin && !isMod) return res.render('403', {});
|
|
275
|
+
return res.render('niki-kasa', { title: 'Niki Kasa' });
|
|
276
|
+
});
|
|
204
277
|
};
|
|
205
278
|
|
|
206
279
|
Plugin.addScripts = async function (scripts) {
|
|
207
|
-
|
|
208
|
-
|
|
280
|
+
scripts.push('plugins/nodebb-plugin-niki-loyalty/static/lib/client.js');
|
|
281
|
+
return scripts;
|
|
209
282
|
};
|
|
210
283
|
|
|
211
284
|
Plugin.addNavigation = async function (nav) {
|
|
212
|
-
|
|
213
|
-
|
|
285
|
+
nav.push({
|
|
286
|
+
route: '/niki-wallet',
|
|
287
|
+
title: 'Niki Cüzdan',
|
|
288
|
+
enabled: true,
|
|
289
|
+
iconClass: 'fa-coffee',
|
|
290
|
+
text: 'Niki Cüzdan',
|
|
291
|
+
});
|
|
292
|
+
return nav;
|
|
214
293
|
};
|
|
215
294
|
|
|
216
|
-
module.exports = Plugin;
|
|
295
|
+
module.exports = Plugin;
|