Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"singleQuote": true,
"printWidth": 120,
"semi": true,
"trailingComma": "none",
"tabWidth": 2,
"useTabs": false,
"bracketSpacing": true,
"arrowParens": "avoid",
"endOfLine": "lf"
}
16 changes: 11 additions & 5 deletions src/controllers/tipController.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,22 @@
* Includes emoji logging for fun debugging experience
*/
import * as tipService from '../services/tipService.js';
import { parsePagination } from '../utils/pagination.js';

/**
* Get all tips
* Get all tips (paginated)
*/
export const getAll = async (req, res, next) => {
try {
console.log('📝 Fetching all tips...');
const tips = await tipService.getAll();
console.log(`✅ Found ${tips.length} tips`);
res.json(tips);
const { page, limit } = parsePagination(req.query, { page: 1, limit: 10 });

console.log(`📝 Fetching tips... page=${page}, limit=${limit}`);

const result = await tipService.getAll({ page, limit });

console.log(`✅ Returned ${result.data.length} tips (total ${result.pagination.totalCount})`);

res.json(result);
} catch (error) {
console.log('❌ Error fetching tips:', error.message);
next(error);
Expand Down
39 changes: 27 additions & 12 deletions src/services/tipService.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import { readFile, writeFile } from 'fs/promises';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
import { paginateArray } from '../utils/pagination.js';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
Expand All @@ -18,7 +19,7 @@ async function readTips() {
const data = await readFile(DATA_FILE, 'utf8');
const parsed = JSON.parse(data);
// Handle both array format and {tips: []} format
return Array.isArray(parsed) ? parsed : (parsed.tips || []);
return Array.isArray(parsed) ? parsed : parsed.tips || [];
} catch (error) {
console.log('⚠️ Could not read tips file, returning empty array');
return [];
Expand All @@ -33,10 +34,18 @@ async function writeTips(tips) {
}

/**
* Get all tips
* Get all tips (optionally paginated)
*
* If pagination is provided -> returns { data, pagination }
* Else (legacy) -> returns full array
*/
export const getAll = async () => {
return readTips();
export const getAll = async (options = undefined) => {
const tips = await readTips();

if (!options) return tips;

const { page = 1, limit = 10 } = options;
return paginateArray(tips, { page, limit });
};

/**
Expand All @@ -52,26 +61,32 @@ export const getRandom = async () => {
/**
* Get tip by ID
*/
export const getById = async (id) => {
export const getById = async id => {
const tips = await readTips();
// Support both string and number IDs
return tips.find(tip => String(tip.id) === String(id));
};

/**
* Get tips by topic
* Get tips by topic (optionally paginated)
*
* If options is provided -> returns { data, pagination }
* Else -> returns array
*/
export const getByTopic = async (topic) => {
export const getByTopic = async (topic, options = undefined) => {
const tips = await readTips();
return tips.filter(tip =>
tip.topic?.toLowerCase() === topic.toLowerCase()
);
const filtered = tips.filter(tip => tip.topic?.toLowerCase() === topic.toLowerCase());

if (!options) return filtered;

const { page = 1, limit = 10 } = options;
return paginateArray(filtered, { page, limit });
};

/**
* Create a new tip
*/
export const create = async (data) => {
export const create = async data => {
const tips = await readTips();
const newTip = {
id: String(tips.length + 1),
Expand Down Expand Up @@ -105,7 +120,7 @@ export const update = async (id, data) => {
/**
* Delete a tip
*/
export const remove = async (id) => {
export const remove = async id => {
const tips = await readTips();
const index = tips.findIndex(tip => String(tip.id) === String(id));
if (index === -1) return false;
Expand Down
39 changes: 39 additions & 0 deletions src/utils/pagination.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* Pagination helpers (reusable for other endpoints)
*/

export function parsePagination(query = {}, defaults = { page: 1, limit: 10 }) {
const pageRaw = query.page;
const limitRaw = query.limit;

const page = toPositiveInt(pageRaw, defaults.page);
const limit = toPositiveInt(limitRaw, defaults.limit);

return { page, limit };
}

export function paginateArray(items, { page = 1, limit = 10 } = {}) {
const totalCount = items.length;

const totalPages = Math.max(1, Math.ceil(totalCount / limit));

const start = (page - 1) * limit;
const end = start + limit;

const data = items.slice(start, end);

return {
data,
pagination: {
currentPage: page,
totalPages,
totalCount,
hasNextPage: page < totalPages,
},
};
}

function toPositiveInt(value, fallback) {
const n = Number.parseInt(value, 10);
return Number.isFinite(n) && n > 0 ? n : fallback;
}