Skip to content

Commit

Permalink
Merge pull request #19 from fac29/status_simplified
Browse files Browse the repository at this point in the history
Simplified status
  • Loading branch information
oskarprzybylski23 authored Aug 5, 2024
2 parents ea2bdc5 + 4f03828 commit a08a553
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 132 deletions.
195 changes: 94 additions & 101 deletions src/routes/goals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,6 @@ import supabase from '../supabaseClient';

const router = express.Router();

// Get all goals for a user
router.get('/user/:userId', async (req, res) => {
try {
const { data, error } = await supabase
.from('user_goals')
.select(`
id,
user_id,
goal_id,
assigned_at,
due_date,
status,
completed_at,
goals (*)
`)
.eq('user_id', req.params.userId);
if (error) throw new Error(error.message);
res.json(data);
} catch (error: unknown) {
res.status(500).json({ error: error instanceof Error ? error.message : 'An unknown error occurred' });
}
});

// Get goal by goal_id
router.get('/:goalId', async (req, res) => {
try {
Expand Down Expand Up @@ -148,7 +125,7 @@ router.delete('/:id', async (req, res) => {
}
});

// Update quiz_selected for multiple user goals
// Update status for multiple user goals. Used by the quiz
router.post('/update-quiz-selected', async (req, res) => {
const { userId, goalIds } = req.body;

Expand All @@ -174,8 +151,7 @@ router.post('/update-quiz-selected', async (req, res) => {
const newUserGoals = goalsToCreate.map(goalId => ({
user_id: userId,
goal_id: goalId,
quiz_selected: true,
status: 'not_done'
status: 'focused'
}));

const { error: insertError } = await supabase
Expand All @@ -188,7 +164,7 @@ router.post('/update-quiz-selected', async (req, res) => {
// Update existing user_goals entries
const { data: updatedGoals, error: updateError } = await supabase
.from('user_goals')
.update({ quiz_selected: true })
.update({ status: 'focused' })
.eq('user_id', userId)
.in('goal_id', goalIds)
.select();
Expand All @@ -208,90 +184,107 @@ router.post('/update-quiz-selected', async (req, res) => {
}
});

router.get('/user-quiz-goals/:userId', async (req, res) => {
// Get all goals sorted by status: completed > focused > not_done
router.get('/user/:userId', async (req, res) => {
const userId = parseInt(req.params.userId);

if (isNaN(userId)) {
return res.status(400).json({ error: 'Invalid userId provided' });
return res.status(400).json({ error: 'Invalid userId provided' });
}

try {
// 1. Fetch user_goals with quiz_selected = true
const { data: selectedUserGoals, error: selectedUserGoalsError } = await supabase
.from('user_goals')
.select(`
goal_id,
quiz_selected,
goals (*)
`)
.eq('user_id', userId)
.eq('quiz_selected', true)
.order('sort_order', { referencedTable: 'goals' });

if (selectedUserGoalsError) throw new Error(selectedUserGoalsError.message);

// 2. Fetch remaining user_goals (quiz_selected = false)
const { data: remainingUserGoals, error: remainingUserGoalsError } = await supabase
.from('user_goals')
.select(`
goal_id,
quiz_selected,
goals (*)
`)
.eq('user_id', userId)
.eq('quiz_selected', false)
.order('sort_order', { referencedTable: 'goals' });

if (remainingUserGoalsError) throw new Error(remainingUserGoalsError.message);

// 3. Fetch all goals
const { data: allGoals, error: allGoalsError } = await supabase
.from('goals')
.select('*')
.order('sort_order');

if (allGoalsError) throw new Error(allGoalsError.message);

// Create a set of goal IDs that are in user_goals
const userGoalIds = new Set([
...selectedUserGoals.map(ug => ug.goal_id),
...remainingUserGoals.map(ug => ug.goal_id)
]);

// Combine the results in the specified order
const combinedGoals = [
...selectedUserGoals.map(ug => ({...ug.goals, quiz_selected: true})),
...remainingUserGoals.map(ug => ({...ug.goals, quiz_selected: false})),
...allGoals.filter(goal => !userGoalIds.has(goal.id)).map(goal => ({...goal, quiz_selected: null}))
];

// Group goals by category
const goalsByCategory = combinedGoals.reduce((acc, goal) => {
if (!acc[goal.category]) {
acc[goal.category] = [];
}
acc[goal.category].push(goal);
return acc;
}, {});

// Create the final structure
const categorizedGoals = Object.entries(goalsByCategory).map(([category, goals]) => ({
category,
goals
}));

res.json({
message: 'Goals fetched successfully',
categorizedGoals
});
// 1. Fetch user_goals with status 'completed'
const { data: completedUserGoals, error: completedUserGoalsError } = await supabase
.from('user_goals')
.select(`
goal_id,
status,
goals (*)
`)
.eq('user_id', userId)
.eq('status', 'completed')
.order('sort_order', { referencedTable: 'goals' });

if (completedUserGoalsError) throw new Error(completedUserGoalsError.message);

// 2. Fetch user_goals with status 'focused'
const { data: focusedUserGoals, error: focusedUserGoalsError } = await supabase
.from('user_goals')
.select(`
goal_id,
status,
goals (*)
`)
.eq('user_id', userId)
.eq('status', 'focused')
.order('sort_order', { referencedTable: 'goals' });

if (focusedUserGoalsError) throw new Error(focusedUserGoalsError.message);

// 3. Fetch user_goals with status 'not_done'
const { data: notDoneUserGoals, error: notDoneUserGoalsError } = await supabase
.from('user_goals')
.select(`
goal_id,
status,
goals (*)
`)
.eq('user_id', userId)
.eq('status', 'not_done')
.order('sort_order', { referencedTable: 'goals' });

if (notDoneUserGoalsError) throw new Error(notDoneUserGoalsError.message);

// 4. Fetch all goals
const { data: allGoals, error: allGoalsError } = await supabase
.from('goals')
.select('*')
.order('sort_order');

if (allGoalsError) throw new Error(allGoalsError.message);

// Create a set of goal IDs that are in user_goals
const userGoalIds = new Set([
...completedUserGoals.map(ug => ug.goal_id),
...focusedUserGoals.map(ug => ug.goal_id),
...notDoneUserGoals.map(ug => ug.goal_id)
]);

// Combine the results in the specified order
const combinedGoals = [
...completedUserGoals.map(ug => ({ ...ug.goals, status: 'completed' })),
...focusedUserGoals.map(ug => ({ ...ug.goals, status: 'focused' })),
...notDoneUserGoals.map(ug => ({ ...ug.goals, status: 'not_done' })),
...allGoals.filter(goal => !userGoalIds.has(goal.id)).map(goal => ({ ...goal, status: null }))
];

// Group goals by category
const goalsByCategory = combinedGoals.reduce((acc, goal) => {
if (!acc[goal.category]) {
acc[goal.category] = [];
}
acc[goal.category].push(goal);
return acc;
}, {});

// Create the final structure
const categorizedGoals = Object.entries(goalsByCategory).map(([category, goals]) => ({
category,
goals
}));

res.json({
message: 'Goals fetched successfully',
categorizedGoals
});

} catch (error: unknown) {
res.status(500).json({
error:
error instanceof Error ? error.message : 'An unknown error occurred',
});
res.status(500).json({
error: error instanceof Error ? error.message : 'An unknown error occurred',
});
}
});



export default router;
11 changes: 6 additions & 5 deletions supabase/migrations/20240729115609_initial_schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,9 @@ CREATE TABLE IF NOT EXISTS
goal_id bigint null,
assigned_at timestamp with time zone not null default now(),
due_date timestamp with time zone null,
status text null default 'not done',
quiz_selected boolean null default false,
status text null default 'not_done',
focus_origin text null default null,
-- quiz_selected boolean null default false,
completed_at timestamp with time zone null,
constraint user_goals_pkey primary key (id),
constraint user_goals_user_id_goal_id_key unique (user_id, goal_id),
Expand All @@ -75,9 +76,9 @@ CREATE TABLE IF NOT EXISTS
(
status = any (
array[
'not_done'::text,
'in_progress'::text,
'completed'::text
'completed'::text,
'focused'::text,
'not_done'::text
]
)
)
Expand Down
16 changes: 8 additions & 8 deletions supabase/seed.sql
Original file line number Diff line number Diff line change
Expand Up @@ -55,20 +55,20 @@ INSERT INTO users (created_at, email, first_name, last_name, password) VALUES

-- Insert user_goals
INSERT INTO user_goals (user_id, goal_id, assigned_at, due_date, status, completed_at) VALUES
(1, 1, '2023-07-01T10:00:00Z', '2023-12-31T23:59:59Z', 'in_progress', NULL),
(1, 2, '2023-07-02T11:30:00Z', '2023-11-30T23:59:59Z', 'completed', '2023-10-15T14:45:00Z'),
(1, 1, '2023-07-01T10:00:00Z', '2023-12-31T23:59:59Z', 'completed', NULL),
(1, 2, '2023-07-02T11:30:00Z', '2023-11-30T23:59:59Z', 'focused', '2023-10-15T14:45:00Z'),
(1, 3, '2023-07-03T09:15:00Z', '2024-01-31T23:59:59Z', 'not_done', NULL),
(1, 4, '2023-07-04T14:00:00Z', '2023-12-15T23:59:59Z', 'in_progress', NULL),
(1, 4, '2023-07-04T14:00:00Z', '2023-12-15T23:59:59Z', 'completed', NULL),
(1, 5, '2023-07-05T16:45:00Z', '2024-02-29T23:59:59Z', 'not_done', NULL),
(2, 1, '2023-07-06T08:30:00Z', '2023-10-31T23:59:59Z', 'completed', '2023-09-30T18:20:00Z'),
(2, 2, '2023-07-07T13:00:00Z', '2024-03-31T23:59:59Z', 'in_progress', NULL),
(2, 1, '2023-07-06T08:30:00Z', '2023-10-31T23:59:59Z', 'focused', '2023-09-30T18:20:00Z'),
(2, 2, '2023-07-07T13:00:00Z', '2024-03-31T23:59:59Z', 'completed', NULL),
(2, 3, '2023-07-08T11:45:00Z', '2023-12-31T23:59:59Z', 'not_done', NULL),
(2, 4, '2023-07-09T10:30:00Z', '2024-01-15T23:59:59Z', 'in_progress', NULL),
(2, 4, '2023-07-09T10:30:00Z', '2024-01-15T23:59:59Z', 'not_done', NULL),
(3, 1, '2023-07-10T15:15:00Z', '2023-11-30T23:59:59Z', 'completed', '2023-11-15T09:30:00Z'),
(3, 2, '2023-07-11T09:45:00Z', '2024-02-28T23:59:59Z', 'in_progress', NULL),
(3, 2, '2023-07-11T09:45:00Z', '2024-02-28T23:59:59Z', 'focused', NULL),
(3, 3, '2023-07-12T14:30:00Z', '2023-12-31T23:59:59Z', 'not_done', NULL),
(4, 1, '2023-07-13T11:00:00Z', '2023-10-31T23:59:59Z', 'completed', '2023-10-20T16:45:00Z'),
(4, 2, '2023-07-14T16:30:00Z', '2024-01-31T23:59:59Z', 'in_progress', NULL),
(4, 2, '2023-07-14T16:30:00Z', '2024-01-31T23:59:59Z', 'not_done', NULL),
(5, 1, '2023-07-15T10:45:00Z', '2023-12-15T23:59:59Z', 'not_done', NULL);

-- Insert questions
Expand Down
33 changes: 15 additions & 18 deletions tests/goals.http
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
### Goals Endpoints ###

# Get all goals for a user REPURPOSE
GET http://localhost:3000/goals/user/2
# Get all goals for a user
GET http://localhost:3000/goals/user/1
# How to use it:
# fetch(`http://localhost:3000/user-quiz-goals/${userId}`)
# .then(response => response.json())
# .then(data => {
# console.log(data.categorizedGoals);
# // data.categorizedGoals will be an array of objects like:
# // [
# // { category: "Category1", goals: [...] },
# // { category: "Category2", goals: [...] },
# // ...
# // ]
# })
# .catch(error => console.error('Error:', error));

### Get goal by goal_id
GET http://localhost:3000/goals/4
Expand Down Expand Up @@ -68,20 +81,4 @@ Content-Type: application/json
# })
# .then(response => response.json())
# .then(result => console.log(result))
# .catch(error => console.error('Error:', error));

### Given a user get all the goals in the right order
GET http://localhost:3000/goals/user-quiz-goals/1
# How to use it:
# fetch(`http://localhost:3000/user-quiz-goals/${userId}`)
# .then(response => response.json())
# .then(data => {
# console.log(data.categorizedGoals);
# // data.categorizedGoals will be an array of objects like:
# // [
# // { category: "Category1", goals: [...] },
# // { category: "Category2", goals: [...] },
# // ...
# // ]
# })
# .catch(error => console.error('Error:', error));

0 comments on commit a08a553

Please sign in to comment.