From 173465f6899f08fa992145fb40c01d6058ae5515 Mon Sep 17 00:00:00 2001 From: Steven Date: Tue, 16 Sep 2025 18:30:38 +0800 Subject: [PATCH 1/5] feat: application page --- functions/index.js | 169 ++++++++++++++++++++++++++++++++++++++++++++- functions/test.js | 99 ++++++++++++++++++++++++++ 2 files changed, 267 insertions(+), 1 deletion(-) create mode 100644 functions/test.js diff --git a/functions/index.js b/functions/index.js index 7be528a..2ab34e7 100644 --- a/functions/index.js +++ b/functions/index.js @@ -211,6 +211,173 @@ exports.getLinksPage = onCall( }, ); +// Application Database ID +const APPLICATION_DATABASE_ID = "270dc74ea0ae803e8904e40ebe203011"; + +// Helper function to create page properties +function createPageProperties(pageData) { + const properties = { + Name: { + title: [{ + text: { content: pageData.name } + }] + }, + Email: { + email: pageData.email + }, + Status: { + select: { name: "Pending" } + }, + "Submission Date": { + date: { start: new Date().toISOString() } + } + }; + + // Add optional fields if provided + if (pageData.role) { + properties.Role = { + select: { name: pageData.role } + }; + } + + if (pageData.motivation && pageData.motivation.trim()) { + properties["Why are you applying?"] = { + rich_text: [{ + text: { content: pageData.motivation } + }] + }; + } + + return properties; +} + +// Helper function to handle API errors +function handleApiError(error, functionName) { + console.error(`Error in ${functionName}:`, error); + return { + success: false, + error: error.message || 'An unexpected error occurred', + details: error + }; +} + +// POST /api/pages - Create a new page +async function createNewPage(pageData) { + try { + // Validate the page data + if (!pageData.name) { + throw new Error('Page name is required'); + } + + if (!pageData.email) { + throw new Error('Email is required'); + } + + // Email format validation + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (!emailRegex.test(pageData.email)) { + throw new Error('Invalid email format'); + } + + // Create the page properties + const properties = createPageProperties(pageData); + + // Create the page in Notion + const newPage = await notion.pages.create({ + parent: { database_id: APPLICATION_DATABASE_ID }, + properties: properties + }); + + return { + success: true, + data: { + id: newPage.id, + url: newPage.url, + created_time: newPage.created_time + }, + message: 'Application submitted successfully' + }; + } catch (error) { + return handleApiError(error, 'createNewPage'); + } +} + +// GET /api/pages/:id - Get page by ID +async function getPageByID(pageId) { + try { + if (!pageId) { + throw new Error('Page ID is required'); + } + + const page = await notion.pages.retrieve({ + page_id: pageId + }); + + const props = page.properties; + + // Parse the page data + const pageData = { + id: page.id, + name: props.Name?.title?.[0]?.plain_text || '', + email: props.Email?.email || '', + status: props.Status?.select?.name || '', + submissionDate: props["Submission Date"]?.date?.start || '', + role: props.Role?.select?.name || null, + motivation: props["Why are you applying?"]?.rich_text?.[0]?.plain_text || null, + created_time: page.created_time, + last_edited_time: page.last_edited_time, + url: page.url + }; + + return { + success: true, + data: pageData, + message: 'Page retrieved successfully' + }; + } catch (error) { + return handleApiError(error, 'getPageByID'); + } +} + +// DELETE /api/pages/:id - Delete (archive) a page +async function deletePage(pageId) { + try { + if (!pageId) { + throw new Error('Page ID is required'); + } + + // Soft delete by updating status to "Archived" + const updatedPage = await notion.pages.update({ + page_id: pageId, + properties: { + Status: { + select: { name: "Archived" } + } + } + }); + + return { + success: true, + data: { + id: updatedPage.id, + status: 'Archived' + }, + message: 'Application archived successfully' + }; + } catch (error) { + return handleApiError(error, 'deletePage'); + } +} + +// Export the application functions +module.exports = { + createNewPage, + getPageByID, + deletePage, + createPageProperties, + handleApiError +}; + // exports.setRiserData = onCall(async (req) => { // console.log(req.data.name); // const result = { @@ -239,4 +406,4 @@ exports.getLinksPage = onCall( // await getFirestore().collection("riserData").add(result); // return { text: "hi" }; -// }); +// }); \ No newline at end of file diff --git a/functions/test.js b/functions/test.js new file mode 100644 index 0000000..2958076 --- /dev/null +++ b/functions/test.js @@ -0,0 +1,99 @@ +// Simple test file for the application API functions +const { createNewPage, getPageByID, deletePage } = require('./index'); + +// Test data +const testApplicationData = { + name: "John Doe", + email: "john.doe@example.com", + role: "Education", + motivation: "I want to help organize amazing hackathons and contribute to the tech community." +}; + +// Test functions +async function runTests() { + console.log('šŸš€ Starting Application API Tests...\n'); + + try { + // Test 1: Create new page + console.log('šŸ“ Test 1: Creating new application...'); + const createResult = await createNewPage(testApplicationData); + console.log('Result:', createResult); + + if (createResult.success) { + const pageId = createResult.data.id; + console.log('āœ… Application created successfully!\n'); + + // Test 2: Get page by ID + console.log('šŸ“– Test 2: Retrieving application...'); + const getResult = await getPageByID(pageId); + console.log('Result:', getResult); + + if (getResult.success) { + console.log('āœ… Application retrieved successfully!\n'); + } else { + console.log('āŒ Failed to retrieve application\n'); + } + + // Test 3: Delete (archive) page + console.log('šŸ—‘ļø Test 3: Archiving application...'); + const deleteResult = await deletePage(pageId); + console.log('Result:', deleteResult); + + if (deleteResult.success) { + console.log('āœ… Application archived successfully!\n'); + } else { + console.log('āŒ Failed to archive application\n'); + } + + } else { + console.log('āŒ Failed to create application\n'); + } + + } catch (error) { + console.error('šŸ’„ Test failed with error:', error); + } + + console.log('šŸ Tests completed!'); +} + +// Test validation +async function testValidation() { + console.log('šŸ” Testing validation...\n'); + + // Test missing name + console.log('Test: Missing name'); + const result1 = await createNewPage({ email: "test@example.com" }); + console.log('Result:', result1); + + // Test missing email + console.log('\nTest: Missing email'); + const result2 = await createNewPage({ name: "Test User" }); + console.log('Result:', result2); + + // Test invalid email + console.log('\nTest: Invalid email'); + const result3 = await createNewPage({ name: "Test User", email: "invalid-email" }); + console.log('Result:', result3); + + console.log('\nāœ… Validation tests completed!\n'); +} + +// Run tests +if (require.main === module) { + console.log('Choose test to run:'); + console.log('1. Full API tests (requires valid Notion setup)'); + console.log('2. Validation tests only'); + + const testType = process.argv[2] || '2'; + + if (testType === '1') { + runTests(); + } else { + testValidation(); + } +} + +module.exports = { + runTests, + testValidation +}; From 2dc29207aa798015801a4c207fa556515a53f978 Mon Sep 17 00:00:00 2001 From: Steven Date: Tue, 16 Sep 2025 18:31:25 +0800 Subject: [PATCH 2/5] simple create function --- functions/index.js | 123 --------------------------------------------- functions/test.js | 89 -------------------------------- 2 files changed, 212 deletions(-) diff --git a/functions/index.js b/functions/index.js index 2ab34e7..c82e7fb 100644 --- a/functions/index.js +++ b/functions/index.js @@ -251,132 +251,9 @@ function createPageProperties(pageData) { return properties; } -// Helper function to handle API errors -function handleApiError(error, functionName) { - console.error(`Error in ${functionName}:`, error); - return { - success: false, - error: error.message || 'An unexpected error occurred', - details: error - }; -} - -// POST /api/pages - Create a new page -async function createNewPage(pageData) { - try { - // Validate the page data - if (!pageData.name) { - throw new Error('Page name is required'); - } - - if (!pageData.email) { - throw new Error('Email is required'); - } - // Email format validation - const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; - if (!emailRegex.test(pageData.email)) { - throw new Error('Invalid email format'); - } - - // Create the page properties - const properties = createPageProperties(pageData); - - // Create the page in Notion - const newPage = await notion.pages.create({ - parent: { database_id: APPLICATION_DATABASE_ID }, - properties: properties - }); - - return { - success: true, - data: { - id: newPage.id, - url: newPage.url, - created_time: newPage.created_time - }, - message: 'Application submitted successfully' - }; - } catch (error) { - return handleApiError(error, 'createNewPage'); - } -} - -// GET /api/pages/:id - Get page by ID -async function getPageByID(pageId) { - try { - if (!pageId) { - throw new Error('Page ID is required'); - } - const page = await notion.pages.retrieve({ - page_id: pageId - }); - - const props = page.properties; - - // Parse the page data - const pageData = { - id: page.id, - name: props.Name?.title?.[0]?.plain_text || '', - email: props.Email?.email || '', - status: props.Status?.select?.name || '', - submissionDate: props["Submission Date"]?.date?.start || '', - role: props.Role?.select?.name || null, - motivation: props["Why are you applying?"]?.rich_text?.[0]?.plain_text || null, - created_time: page.created_time, - last_edited_time: page.last_edited_time, - url: page.url - }; - - return { - success: true, - data: pageData, - message: 'Page retrieved successfully' - }; - } catch (error) { - return handleApiError(error, 'getPageByID'); - } -} - -// DELETE /api/pages/:id - Delete (archive) a page -async function deletePage(pageId) { - try { - if (!pageId) { - throw new Error('Page ID is required'); - } - - // Soft delete by updating status to "Archived" - const updatedPage = await notion.pages.update({ - page_id: pageId, - properties: { - Status: { - select: { name: "Archived" } - } - } - }); - - return { - success: true, - data: { - id: updatedPage.id, - status: 'Archived' - }, - message: 'Application archived successfully' - }; - } catch (error) { - return handleApiError(error, 'deletePage'); - } -} -// Export the application functions -module.exports = { - createNewPage, - getPageByID, - deletePage, - createPageProperties, - handleApiError -}; // exports.setRiserData = onCall(async (req) => { // console.log(req.data.name); diff --git a/functions/test.js b/functions/test.js index 2958076..8f529ab 100644 --- a/functions/test.js +++ b/functions/test.js @@ -8,92 +8,3 @@ const testApplicationData = { role: "Education", motivation: "I want to help organize amazing hackathons and contribute to the tech community." }; - -// Test functions -async function runTests() { - console.log('šŸš€ Starting Application API Tests...\n'); - - try { - // Test 1: Create new page - console.log('šŸ“ Test 1: Creating new application...'); - const createResult = await createNewPage(testApplicationData); - console.log('Result:', createResult); - - if (createResult.success) { - const pageId = createResult.data.id; - console.log('āœ… Application created successfully!\n'); - - // Test 2: Get page by ID - console.log('šŸ“– Test 2: Retrieving application...'); - const getResult = await getPageByID(pageId); - console.log('Result:', getResult); - - if (getResult.success) { - console.log('āœ… Application retrieved successfully!\n'); - } else { - console.log('āŒ Failed to retrieve application\n'); - } - - // Test 3: Delete (archive) page - console.log('šŸ—‘ļø Test 3: Archiving application...'); - const deleteResult = await deletePage(pageId); - console.log('Result:', deleteResult); - - if (deleteResult.success) { - console.log('āœ… Application archived successfully!\n'); - } else { - console.log('āŒ Failed to archive application\n'); - } - - } else { - console.log('āŒ Failed to create application\n'); - } - - } catch (error) { - console.error('šŸ’„ Test failed with error:', error); - } - - console.log('šŸ Tests completed!'); -} - -// Test validation -async function testValidation() { - console.log('šŸ” Testing validation...\n'); - - // Test missing name - console.log('Test: Missing name'); - const result1 = await createNewPage({ email: "test@example.com" }); - console.log('Result:', result1); - - // Test missing email - console.log('\nTest: Missing email'); - const result2 = await createNewPage({ name: "Test User" }); - console.log('Result:', result2); - - // Test invalid email - console.log('\nTest: Invalid email'); - const result3 = await createNewPage({ name: "Test User", email: "invalid-email" }); - console.log('Result:', result3); - - console.log('\nāœ… Validation tests completed!\n'); -} - -// Run tests -if (require.main === module) { - console.log('Choose test to run:'); - console.log('1. Full API tests (requires valid Notion setup)'); - console.log('2. Validation tests only'); - - const testType = process.argv[2] || '2'; - - if (testType === '1') { - runTests(); - } else { - testValidation(); - } -} - -module.exports = { - runTests, - testValidation -}; From 86fbf7f514dd8e701defa123a21b8a2b929bd9a6 Mon Sep 17 00:00:00 2001 From: flatplum Date: Tue, 23 Sep 2025 23:11:30 +1000 Subject: [PATCH 3/5] feat: remove hackmelbourne from navbar Reasoning being extraneous information, and adds room for "Join Us" item. --- src/layouts/Navbar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layouts/Navbar.tsx b/src/layouts/Navbar.tsx index 504a30c..5eedf3e 100644 --- a/src/layouts/Navbar.tsx +++ b/src/layouts/Navbar.tsx @@ -139,7 +139,7 @@ const Navbar = ({ clubname, logo, pages, links, pills }: Nav) => {
- {clubname} + {/* {clubname} */}