diff --git a/components/ArchiveSummaries.tsx b/components/ArchiveSummaries.tsx index f9b97b9..7110713 100644 --- a/components/ArchiveSummaries.tsx +++ b/components/ArchiveSummaries.tsx @@ -56,30 +56,44 @@ const ArchiveSummaries = () => { } }; - async function handleSubmit(e: any) { + async function handleSubmit(e: React.FormEvent) { e.preventDefault(); setLoading(true); - if (myVariable.summary.confirmed == false) { + + // Check if there are any confirmed summaries with the same date + const isDuplicateConfirmedSummary = myVariable.summaries.some((summary: any) => { + // Convert both dates to Date objects to strip off the time part + const summaryDate = new Date(summary.date).toDateString(); + const formDataDate = new Date(formData.date).toDateString(); + //console.log(summaryDate, formDataDate, summaryDate === formDataDate && summary.confirmed); // For debugging purposes + // Compare the date strings + return summaryDate === formDataDate && summary.confirmed; + }); + + if (isDuplicateConfirmedSummary) { + alert('A confirmed summary for this date already exists.'); + setLoading(false); + return; // Exit the function early + } + + if (!myVariable.summary.confirmed) { const data = await updateGitbook(formData); - //console.log("returned from util function", formData) if (data) { - setMyVariable({ - ...myVariable, + setMyVariable(prevState => ({ + ...prevState, summary: { - ...myVariable.summary, + ...prevState.summary, confirmed: true, }, - }); + })); } - //console.log(myVariable) await sendDiscordMessage(myVariable, renderedMarkdown); - //console.log(myVariable, "renderedMarkdown", renderedMarkdown) } else { - alert('Summary already archived') + alert('Summary already archived'); } setLoading(false); - } + } return (
diff --git a/components/SubmitMissingSummary.tsx b/components/SubmitMissingSummary.tsx index 3434d4e..0baa65e 100644 --- a/components/SubmitMissingSummary.tsx +++ b/components/SubmitMissingSummary.tsx @@ -5,50 +5,52 @@ import { saveMissingSummary } from '../utils/saveMissingSummaries'; function formatDate(dateString: any) { const options = { year: 'numeric', month: 'long', day: 'numeric' }; const date = new Date(dateString); - // Manually construct the date string to ensure it's in "DD MMMM YYYY" format const formattedDate = `${date.getDate()} ${date.toLocaleString('en-US', { month: 'long' })} ${date.getFullYear()}`; return formattedDate; - } +} -const SubmitMissingSummary = ({ workgroups, allSummaries }: any) => { +const SubmitMissingSummary = ({ workgroups, allSummaries, allArchivedSummaries }: any) => { const [selectedWorkgroup, setSelectedWorkgroup] = useState<{ workgroup: string; workgroup_id: string; } | null>(null); const [meetingDate, setMeetingDate] = useState(''); - //console.log("allSummaries", allSummaries) const handleSubmit = async (e: any) => { e.preventDefault(); if (selectedWorkgroup && meetingDate) { const missingSummaryData = { workgroup: selectedWorkgroup.workgroup, workgroupId: selectedWorkgroup.workgroup_id, - meetingDate: formatDate(meetingDate), // Assuming you want the formatted date here + meetingDate: formatDate(meetingDate), status: "Missing", type: "weekly" }; + + // Combine allSummaries and allArchivedSummaries, considering all as "Done" for conflict checking + const combinedSummaries = [...allSummaries, ...allArchivedSummaries.map((summary: any) => ({...summary, status: "Done"}))]; + const newRow = { meetingDate: formatDate(meetingDate), workgroup: selectedWorkgroup.workgroup, status: "Missing" }; - const conflictSummary = allSummaries.find((summary: any) => + const conflictSummary = combinedSummaries.find((summary: any) => summary.meetingDate === newRow.meetingDate && summary.workgroup === newRow.workgroup ); - // If a "Done" summary exists for the same meetingDate and workgroup, alert the user - if (conflictSummary && conflictSummary.status === "Done") { - alert("This meeting is already marked as Done."); + // If a summary exists for the same meetingDate and workgroup, alert the user + if (conflictSummary) { + alert(`This meeting is already marked as ${conflictSummary.status}.`); return; // Prevent the submission } - const summariesToUpdate = newRow ? [...allSummaries, newRow] : allSummaries; + const summariesToUpdate = [...combinedSummaries, newRow]; try { - // First, save the missing summary through your existing utility function + // Save the missing summary const saveResponse = await saveMissingSummary(missingSummaryData); console.log('Save missing summary response:', saveResponse); - // If the save operation is successful, then update the CSV in GitHub + // Update the CSV in GitHub const response = await fetch('/api/updateCSV', { method: 'POST', headers: { 'Content-Type': 'application/json' }, @@ -67,15 +69,13 @@ const SubmitMissingSummary = ({ workgroups, allSummaries }: any) => { const responseData = await response.json(); console.log('CSV updated successfully:', responseData); - // Reset form state here setSelectedWorkgroup(null); setMeetingDate(''); } catch (error) { console.error('Error:', error); - // Handle error, e.g., showing an error message } } - }; + }; return (
diff --git a/components/SummaryAgendaItems.tsx b/components/SummaryAgendaItems.tsx index 15cc76f..0421c9f 100644 --- a/components/SummaryAgendaItems.tsx +++ b/components/SummaryAgendaItems.tsx @@ -3,27 +3,29 @@ import { useMyVariable } from '../context/MyVariableContext'; import styles from '../styles/typea.module.css'; import Item from './Item'; import { getDefaultAgendaItem } from '../utils/getDefaultAgendaItem'; +import { filterFormData } from '../utils/filterFormData'; -const SummaryAgendaItems = ({onUpdate}: any) => { - const { myVariable, setMyVariable } = useMyVariable(); - const initialAgendaItems = myVariable?.summary?.agendaItems?.map((item: any) => ({ - ...getDefaultAgendaItem(), - ...item - })) || [getDefaultAgendaItem()]; +const SummaryAgendaItems = ({ onUpdate }: any) => { + const { myVariable, setMyVariable } = useMyVariable(); + const formData = filterFormData(myVariable?.summary); + const initialAgendaItems = formData.agendaItems?.map((item: any) => ({ + ...getDefaultAgendaItem(), + ...item + })) || [getDefaultAgendaItem()]; const [agendaItems, setAgendaItems] = useState(initialAgendaItems); - + useEffect(() => { onUpdate(agendaItems); //console.log("agendaItems", agendaItems) }, [agendaItems]); useEffect(() => { - const agendaItemsFromVariable = myVariable.summary?.agendaItems?.map((item: any) => ({ + const agendaItemsFromVariable = formData.agendaItems?.map((item: any) => ({ ...getDefaultAgendaItem(), ...item })) || [getDefaultAgendaItem()]; - + setAgendaItems(agendaItemsFromVariable); }, [myVariable.summary?.agendaItems]); @@ -41,14 +43,14 @@ const SummaryAgendaItems = ({onUpdate}: any) => { const newAgendaItems: any = [...agendaItems]; if (type === 'actionItems') { newAgendaItems[agendaIndex][type].push({ text: "", assignee: "", dueDate: "", status: "todo" }); - } else if (type === 'decisionItems') { + } else if (type === 'decisionItems') { newAgendaItems[agendaIndex][type].push({ decision: "", rationale: "", opposing: "", effect: "" }); } else { newAgendaItems[agendaIndex][type].push(""); } setAgendaItems(newAgendaItems); }; - + const removeItem = (type: string, agendaIndex: number, itemIndex: number) => { const newAgendaItems: any = [...agendaItems]; @@ -58,293 +60,293 @@ const SummaryAgendaItems = ({onUpdate}: any) => { const handleItemUpdate = (type: any, agendaIdx: any, itemIdx: any, updatedItem: any) => { setAgendaItems((prevAgendaItems: any) => { - const newAgendaItems = JSON.parse(JSON.stringify(prevAgendaItems)); + const newAgendaItems = JSON.parse(JSON.stringify(prevAgendaItems)); - // Check if the type is 'narrative' - if (type === 'townHallUpdates' || type === 'narrative' || type === 'gameRules' || type === 'townHallSummary') { - if (newAgendaItems[agendaIdx]) { - newAgendaItems[agendaIdx][type] = updatedItem[type]; // Directly set the narrative or gameRules string - } - } else { - // Handle other types as before - if (newAgendaItems[agendaIdx] && newAgendaItems[agendaIdx][type]) { - newAgendaItems[agendaIdx][type][itemIdx] = updatedItem; - } + // Check if the type is 'narrative' + if (type === 'townHallUpdates' || type === 'narrative' || type === 'gameRules' || type === 'townHallSummary') { + if (newAgendaItems[agendaIdx]) { + newAgendaItems[agendaIdx][type] = updatedItem[type]; // Directly set the narrative or gameRules string + } + } else { + // Handle other types as before + if (newAgendaItems[agendaIdx] && newAgendaItems[agendaIdx][type]) { + newAgendaItems[agendaIdx][type][itemIdx] = updatedItem; } + } - return newAgendaItems; + return newAgendaItems; }); -}; + }; -const getHeading = (itemType: any, workgroup: any) => { - switch(itemType) { - case "issues": - if(workgroup === "Onboarding Workgroup") return "To carry over for next meeting"; - // Add more specific conditions for "issues" if needed - return "Issues"; // Default for "issues" + const getHeading = (itemType: any, workgroup: any) => { + switch (itemType) { + case "issues": + if (workgroup === "Onboarding Workgroup") return "To carry over for next meeting"; + // Add more specific conditions for "issues" if needed + return "Issues"; // Default for "issues" - case "discussionPoints": - if(workgroup === "Onboarding Workgroup") return "In this meeting we discussed"; - return "Discussion Points"; + case "discussionPoints": + if (workgroup === "Onboarding Workgroup") return "In this meeting we discussed"; + return "Discussion Points"; - case "meetingTopics": - if(workgroup === "Research and Development Guild") return "Agenda Items"; - if(workgroup === "Education Workgroup") return "In this meeting we discussed"; - return "Meeting Topics"; - // Add cases for other item types as needed + case "meetingTopics": + if (workgroup === "Research and Development Guild") return "Agenda Items"; + if (workgroup === "Education Workgroup") return "In this meeting we discussed"; + return "Meeting Topics"; + // Add cases for other item types as needed - default: - return "Items"; + default: + return "Items"; + } } -} const itemTypesConfig = [ - { - type: "townHallUpdates", - isEnabled: (template: any) => template?.townHallUpdates === 1, - render: (item: any, agendaIndex: any) => ( - <> -

Town Hall Updates from this meeting

-
- handleItemUpdate('townHallUpdates', agendaIdx, itemIdx, updatedItem)} - onRemove={removeItem} - /> -
- - ) - }, - { - type: "narrative", - isEnabled: (template: any) => template?.narrative === 1, - render: (item: any, agendaIndex: any) => ( - <> -

Narrative

-
- handleItemUpdate('narrative', agendaIdx, itemIdx, updatedItem)} - onRemove={removeItem} - /> -
- - ) - }, - { - type: "meetingTopics", - isEnabled: (template: any) => template?.meetingTopics === 1, - render: (item: any, agendaIndex: any) => ( - <> -

{getHeading("meetingTopics", myVariable.workgroup?.preferred_template?.workgroup)}

-
- {item.meetingTopics.map((point: any, pointIndex: any) => ( + { + type: "townHallUpdates", + isEnabled: (template: any) => template?.townHallUpdates === 1, + render: (item: any, agendaIndex: any) => ( + <> +

Town Hall Updates from this meeting

+
+ handleItemUpdate('townHallUpdates', agendaIdx, itemIdx, updatedItem)} + onRemove={removeItem} + /> +
+ + ) + }, + { + type: "narrative", + isEnabled: (template: any) => template?.narrative === 1, + render: (item: any, agendaIndex: any) => ( + <> +

Narrative

+
+ handleItemUpdate('narrative', agendaIdx, itemIdx, updatedItem)} + onRemove={removeItem} + /> +
+ + ) + }, + { + type: "meetingTopics", + isEnabled: (template: any) => template?.meetingTopics === 1, + render: (item: any, agendaIndex: any) => ( + <> +

{getHeading("meetingTopics", myVariable.workgroup?.preferred_template?.workgroup)}

+
+ {item.meetingTopics.map((point: any, pointIndex: any) => ( handleItemUpdate('meetingTopics', agendaIdx, itemIdx, updatedItem)} - onRemove={removeItem} + key={`${agendaIndex}-meetingtopic-${pointIndex}`} + type="meetingTopics" + item={point} + agendaIndex={agendaIndex} + itemIndex={pointIndex} + onUpdate={(agendaIdx: any, itemIdx: any, updatedItem: any) => handleItemUpdate('meetingTopics', agendaIdx, itemIdx, updatedItem)} + onRemove={removeItem} /> ))} -
- - - ) - }, - { - type: "discussionPoints", - isEnabled: (template: any) => template?.discussionPoints === 1, - render: (item: any, agendaIndex: any) => ( - <> -

{getHeading("discussionPoints", myVariable.workgroup?.preferred_template?.workgroup)}

-
- {item.discussionPoints.map((point: any, pointIndex: any) => ( +
+ + + ) + }, + { + type: "discussionPoints", + isEnabled: (template: any) => template?.discussionPoints === 1, + render: (item: any, agendaIndex: any) => ( + <> +

{getHeading("discussionPoints", myVariable.workgroup?.preferred_template?.workgroup)}

+
+ {item.discussionPoints.map((point: any, pointIndex: any) => ( handleItemUpdate('discussionPoints', agendaIdx, itemIdx, updatedItem)} - onRemove={removeItem} + key={`${agendaIndex}-discussion-${pointIndex}`} + type="discussionPoints" + item={point} + agendaIndex={agendaIndex} + itemIndex={pointIndex} + onUpdate={(agendaIdx: any, itemIdx: any, updatedItem: any) => handleItemUpdate('discussionPoints', agendaIdx, itemIdx, updatedItem)} + onRemove={removeItem} /> ))} -
- - - ) - }, - { - type: "actionItems", - isEnabled: (template: any) => template?.actionItems === 1, - render: (item: any, agendaIndex: any) => ( - <> -

Action items

- {item?.actionItems?.map((action: any, actionIndex: any) => ( - handleItemUpdate('actionItems', agendaIdx, itemIdx, updatedItem)} - onRemove={removeItem} - /> - ))} - - - ) - }, - { - type: "decisionItems", - isEnabled: (template: any) => template?.decisionItems === 1, - render: (item: any, agendaIndex: any) => ( - <> -

Decisions

- {item?.decisionItems?.map((decision: any, decisionIndex: any) => ( +
+ + + ) + }, + { + type: "actionItems", + isEnabled: (template: any) => template?.actionItems === 1, + render: (item: any, agendaIndex: any) => ( + <> +

Action items

+ {item?.actionItems?.map((action: any, actionIndex: any) => ( handleItemUpdate('decisionItems', agendaIdx, itemIdx, updatedItem)} - onRemove={removeItem} - /> - ))} - - - ) - }, - { - type: "gameRules", - isEnabled: (template: any) => template?.gameRules === 1, - render: (item: any, agendaIndex: any) => ( - <> -

Game Rules

-
- handleItemUpdate('gameRules', agendaIdx, itemIdx, updatedItem)} - onRemove={removeItem} - /> -
- - ) - }, - { - type: "townHallSummary", - isEnabled: (template: any) => template?.townHallSummary === 1, - render: (item: any, agendaIndex: any) => ( - <> -

Town Hall Summary (Optional)

-
- handleItemUpdate('townHallSummary', agendaIdx, itemIdx, updatedItem)} - onRemove={removeItem} - /> -
- - ) - }, - { - type: "leaderboard", - isEnabled: (template: any) => template?.leaderboard === 1, - render: (item: any, agendaIndex: any) => ( - <> -

Leaderboard

-
- {item.leaderboard.map((point: any, pointIndex: any) => ( + key={`${agendaIndex}-action-${actionIndex}`} + type="actionItems" + item={action} + agendaIndex={agendaIndex} + itemIndex={actionIndex} + onUpdate={(agendaIdx: any, itemIdx: any, updatedItem: any) => handleItemUpdate('actionItems', agendaIdx, itemIdx, updatedItem)} + onRemove={removeItem} + /> + ))} + + + ) + }, + { + type: "decisionItems", + isEnabled: (template: any) => template?.decisionItems === 1, + render: (item: any, agendaIndex: any) => ( + <> +

Decisions

+ {item?.decisionItems?.map((decision: any, decisionIndex: any) => ( + handleItemUpdate('decisionItems', agendaIdx, itemIdx, updatedItem)} + onRemove={removeItem} + /> + ))} + + + ) + }, + { + type: "gameRules", + isEnabled: (template: any) => template?.gameRules === 1, + render: (item: any, agendaIndex: any) => ( + <> +

Game Rules

+
+ handleItemUpdate('gameRules', agendaIdx, itemIdx, updatedItem)} + onRemove={removeItem} + /> +
+ + ) + }, + { + type: "townHallSummary", + isEnabled: (template: any) => template?.townHallSummary === 1, + render: (item: any, agendaIndex: any) => ( + <> +

Town Hall Summary (Optional)

+
+ handleItemUpdate('townHallSummary', agendaIdx, itemIdx, updatedItem)} + onRemove={removeItem} + /> +
+ + ) + }, + { + type: "leaderboard", + isEnabled: (template: any) => template?.leaderboard === 1, + render: (item: any, agendaIndex: any) => ( + <> +

Leaderboard

+
+ {item.leaderboard.map((point: any, pointIndex: any) => ( handleItemUpdate('leaderboard', agendaIdx, itemIdx, updatedItem)} - onRemove={removeItem} + key={`${agendaIndex}-leaderboard-${pointIndex}`} + type="leaderboard" + item={point} + agendaIndex={agendaIndex} + itemIndex={pointIndex} + onUpdate={(agendaIdx: any, itemIdx: any, updatedItem: any) => handleItemUpdate('leaderboard', agendaIdx, itemIdx, updatedItem)} + onRemove={removeItem} /> ))} -
- - - ) - }, - { - type: "learningPoints", - isEnabled: (template: any) => template?.learningPoints === 1, - render: (item: any, agendaIndex: any) => ( - <> -

Learning Points

-
- {item.learningPoints.map((point: any, pointIndex: any) => ( +
+ + + ) + }, + { + type: "learningPoints", + isEnabled: (template: any) => template?.learningPoints === 1, + render: (item: any, agendaIndex: any) => ( + <> +

Learning Points

+
+ {item.learningPoints.map((point: any, pointIndex: any) => ( handleItemUpdate('learningPoints', agendaIdx, itemIdx, updatedItem)} - onRemove={removeItem} + key={`${agendaIndex}-learning-${pointIndex}`} + type="learningPoints" + item={point} + agendaIndex={agendaIndex} + itemIndex={pointIndex} + onUpdate={(agendaIdx: any, itemIdx: any, updatedItem: any) => handleItemUpdate('learningPoints', agendaIdx, itemIdx, updatedItem)} + onRemove={removeItem} /> ))} -
- - - ) - }, - { - type: "issues", - isEnabled: (template: any) => template?.issues === 1, - render: (item: any, agendaIndex: any) => ( - <> -

{getHeading("issues", myVariable.workgroup?.preferred_template?.workgroup)}

-
- {item?.issues?.map((issue: any, issueIndex: any) => ( - handleItemUpdate('issues', agendaIdx, itemIdx, updatedItem)} - onRemove={removeItem} - /> - ))} - -
- - ) - }, - /*{ - type: "issues", - isEnabled: (template: any) => template.issues === 1, - render: (item: any, agendaIndex: any) => ( - // ... rendering logic for issues ... - ) - },*/ -]; +
+ + + ) + }, + { + type: "issues", + isEnabled: (template: any) => template?.issues === 1, + render: (item: any, agendaIndex: any) => ( + <> +

{getHeading("issues", myVariable.workgroup?.preferred_template?.workgroup)}

+
+ {item?.issues?.map((issue: any, issueIndex: any) => ( + handleItemUpdate('issues', agendaIdx, itemIdx, updatedItem)} + onRemove={removeItem} + /> + ))} + +
+ + ) + }, + /*{ + type: "issues", + isEnabled: (template: any) => template.issues === 1, + render: (item: any, agendaIndex: any) => ( + // ... rendering logic for issues ... + ) + },*/ + ]; -type WorkgroupKey = keyof typeof orderMapping; + type WorkgroupKey = keyof typeof orderMapping; -const orderMapping = myVariable.agendaItemOrder; /*{ + const orderMapping = myVariable?.agendaItemOrder; /*{ "Gamers Guild": ["narrative", "decisionItems", "actionItems", "gameRules", "leaderboard"], "Writers Workgroup": ["narrative", "decisionItems", "actionItems", "learningPoints"], "Video Workgroup": ["discussionPoints", "decisionItems", "actionItems"], @@ -357,31 +359,31 @@ const orderMapping = myVariable.agendaItemOrder; /*{ "Governance Workgroup": ["narrative", "decisionItems", "actionItems", "DiscussionPoints"] };*/ -const reorderItemTypesConfig = (orderKey: WorkgroupKey) => { - const order = orderMapping[orderKey]; - if (!order) { - console.warn("Order key not found in mapping"); - return; - } + const reorderItemTypesConfig = (orderKey: WorkgroupKey) => { + const order = orderMapping[orderKey]; + if (!order) { + console.warn("Order key not found in mapping"); + return; + } - itemTypesConfig.sort((a, b) => { - const indexA = order.indexOf(a.type); - const indexB = order.indexOf(b.type); - - if (indexA === -1 && indexB === -1) return 0; // Both types are not in the order list, keep their relative order - if (indexA === -1) return 1; // Type A is not in the list, move it towards the end - if (indexB === -1) return -1; // Type B is not in the list, move it towards the end - - return indexA - indexB; - }); - -}; + itemTypesConfig.sort((a, b) => { + const indexA = order.indexOf(a.type); + const indexB = order.indexOf(b.type); + + if (indexA === -1 && indexB === -1) return 0; // Both types are not in the order list, keep their relative order + if (indexA === -1) return 1; // Type A is not in the list, move it towards the end + if (indexB === -1) return -1; // Type B is not in the list, move it towards the end -if (typeof myVariable.workgroup?.workgroup === 'string' && myVariable.workgroup?.workgroup in orderMapping) { - reorderItemTypesConfig(myVariable.workgroup?.workgroup as WorkgroupKey); -} else { - console.warn("Invalid workgroup key"); -} + return indexA - indexB; + }); + + }; + + if (typeof myVariable.workgroup?.workgroup === 'string' && myVariable.workgroup?.workgroup in orderMapping) { + reorderItemTypesConfig(myVariable.workgroup?.workgroup as WorkgroupKey); + } else { + console.warn("Invalid workgroup key"); + } return (
@@ -391,45 +393,45 @@ if (typeof myVariable.workgroup?.workgroup === 'string' && myVariable.workgroup? {myVariable.workgroup?.preferred_template?.agendaItems[0]?.agenda == 1 && ( <>

Agenda item {agendaIndex + 1}

-
-
+
+
- { - const newAgenda = [...agendaItems]; - newAgenda[agendaIndex].agenda = e.target.value; - setAgendaItems(newAgenda); - }} - /> -
-
- - -
+ { + const newAgenda = [...agendaItems]; + newAgenda[agendaIndex].agenda = e.target.value; + setAgendaItems(newAgenda); + }} + /> +
+
+ + +
)} - + {itemTypesConfig.map(({ type, isEnabled, render }) => { if (isEnabled(myVariable.workgroup?.preferred_template?.agendaItems[0])) { // Add a unique key prop to each rendered element diff --git a/components/SummaryTemplate.tsx b/components/SummaryTemplate.tsx index 45aa5c0..260a139 100644 --- a/components/SummaryTemplate.tsx +++ b/components/SummaryTemplate.tsx @@ -7,6 +7,7 @@ import Tags from './Tags' import { saveCustomAgenda } from '../utils/saveCustomAgenda'; import { generateMarkdown } from '../utils/generateMarkdown'; import axios from "axios"; +import { filterFormData } from '../utils/filterFormData'; type SummaryTemplateProps = { updateMeetings: (newMeetingSummary: any) => void; @@ -109,7 +110,7 @@ const SummaryTemplate = ({ updateMeetings }: SummaryTemplateProps) => { type: "Custom" }; - const [formData, setFormData] = useState(filterKeys(myVariable.summary || {}, defaultFormData)); + const [formData, setFormData] = useState(filterFormData(filterKeys(myVariable.summary || {}, defaultFormData))); const [tags, setTags] = useState({ topicsCovered: "", emotions: "", other: "", gamesPlayed: "" }); const currentOrder = myVariable.agendaItemOrder ? myVariable.agendaItemOrder[myVariable.workgroup?.workgroup] : undefined; @@ -168,7 +169,7 @@ const SummaryTemplate = ({ updateMeetings }: SummaryTemplateProps) => { useEffect(() => { // Set the local state whenever myVariable.summary changes - setFormData(filterKeys(myVariable.summary || {}, defaultFormData)); + setFormData((filterKeys(myVariable.summary || {}, defaultFormData))); //console.log(myVariable, generateMarkdown(myVariable.summary, currentOrder)) }, [myVariable.summary]); // Add myVariable.summary to the dependency array @@ -183,6 +184,7 @@ const SummaryTemplate = ({ updateMeetings }: SummaryTemplateProps) => { useEffect(() => { setFormData((prevState: any) => ({ ...prevState, tags })); + //console.log("formData",formData, myVariable) }, [tags]); const removeEmptyValues = (obj: any) => { @@ -241,6 +243,8 @@ const SummaryTemplate = ({ updateMeetings }: SummaryTemplateProps) => { }, updated_at: new Date() } + + summary.confirmed = false; const cleanedFormData = removeEmptyValues({ ...formData, meetingInfo: { ...formData.meetingInfo, workingDocs: filteredWorkingDocs } }); setLoading(true); diff --git a/context/MyVariableContext.tsx b/context/MyVariableContext.tsx index a0006d6..30c3094 100644 --- a/context/MyVariableContext.tsx +++ b/context/MyVariableContext.tsx @@ -27,6 +27,7 @@ type MyVariable = { tags?: any; currentUser?: string; agendaItemOrder: any; + selectedDate: any; // other keys go here }; @@ -42,7 +43,7 @@ interface MyVariableProviderProps { } export const MyVariableProvider: React.FC = ({ children }) => { - const [myVariable, setMyVariable] = useState({ groupInfo: [], projectInfo: undefined, workgroup: undefined, summaries: undefined, summary: undefined, roles: undefined, isLoggedIn: undefined, names: [], tags: {}, currentUser: "", agendaItemOrder: {} }); + const [myVariable, setMyVariable] = useState({ groupInfo: [], projectInfo: undefined, workgroup: undefined, summaries: undefined, summary: undefined, roles: undefined, isLoggedIn: undefined, names: [], tags: {}, currentUser: "", agendaItemOrder: {}, selectedDate: undefined }); return ( diff --git a/pages/api/getMeetingSummaries.js b/pages/api/getMeetingSummaries.js index f1b1b58..6826c8a 100644 --- a/pages/api/getMeetingSummaries.js +++ b/pages/api/getMeetingSummaries.js @@ -19,11 +19,12 @@ export default async function handler(req, res) { try { let { data, error } = await supabase .from('meetingsummaries') - .select('summary, updated_at, confirmed'); + .select('summary, updated_at, confirmed') + .eq('confirmed', true); if (error) throw error; - // Set CORS headers + // Set CORS headers for the actual request res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET'); res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, api_key'); @@ -32,4 +33,4 @@ export default async function handler(req, res) { } catch (error) { res.status(500).json({ error: error.message }); } -} \ No newline at end of file +} diff --git a/pages/api/issues.js b/pages/api/issues.js index 02ab06e..89b706d 100644 --- a/pages/api/issues.js +++ b/pages/api/issues.js @@ -6,14 +6,17 @@ export default async function handler(req, res) { const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN }); try { - const issues = await octokit.paginate(octokit.rest.issues.listForRepo, { + const allIssuesAndPRs = await octokit.paginate(octokit.rest.issues.listForRepo, { owner: 'SingularityNET-Archive', repo: 'archive-oracle', state: 'all', per_page: 100, // Adjust per_page to your needs }); - res.status(200).json(issues); + // Filter out pull requests from the issues + const issuesOnly = allIssuesAndPRs.filter(issue => !issue.pull_request); + + res.status(200).json(issuesOnly); } catch (error) { console.error("Failed to fetch issues:", error); res.status(500).json({ error: error.message }); diff --git a/pages/index.tsx b/pages/index.tsx index 877d466..4a6d11d 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -5,10 +5,10 @@ import axios from 'axios'; const Home: NextPage = () => { const [loading, setLoading] = useState(false); - /*useEffect(() => { + /*useEffect(() => { // Used for testing the API const fetchMeetingSummaries = async () => { - const SERVER_API_URL = 'https://archive-oracle.netlify.app/api/getMeetingSummaries'; - const API_KEY = process.env.SERVER_API_KEY; + const SERVER_API_URL = '/api/getMeetingSummaries'; + const API_KEY = process.env.NEXT_PUBLIC_SERVER_API_KEY; setLoading(true); // Start loading try { diff --git a/pages/status-of-summaries.tsx b/pages/status-of-summaries.tsx index bc37b0b..30dd837 100644 --- a/pages/status-of-summaries.tsx +++ b/pages/status-of-summaries.tsx @@ -17,6 +17,7 @@ const StatusOfSummaries: NextPage = () => { const [data, setData] = useState([]); const [workgroups, setWorkgroups] = useState([]); const [allSummaries, setAllSummaries] = useState([]); + const [archivedSummaries, setArchivedSummaries] = useState([]); async function fetchCsvData() { setLoading(true); @@ -39,8 +40,11 @@ const StatusOfSummaries: NextPage = () => { async function fetchWorkgroups() { try { const databaseWorkgroups = await getWorkgroups(); - const allSummaries = await getMissingSummaries(); + const { finalSummaries, allArchivedSummaries } = await getMissingSummaries(); + const allSummaries = finalSummaries; setAllSummaries(allSummaries) + setArchivedSummaries(allArchivedSummaries); + //console.log("allSummaries", allSummaries) // Assuming databaseWorkgroups should be an array, check and handle accordingly if (Array.isArray(databaseWorkgroups)) { @@ -58,7 +62,7 @@ const StatusOfSummaries: NextPage = () => { return (
- +

Status of Summaries

{loading &&

Loading...

} @@ -85,7 +89,7 @@ const StatusOfSummaries: NextPage = () => { {/* Done Summaries Table */} -

Done Summaries

+

Done Summaries (Needs to be archived)

@@ -104,6 +108,27 @@ const StatusOfSummaries: NextPage = () => { ))}
+ + {/* Archived Summaries Table */} +

Archived Summaries

+ + + + + + + + + + {archivedSummaries.map((row, index) => ( + + + + + + ))} + +
Meeting DateWorkgroupStatus
{row.meetingDate}{row.workgroup}{row.status}
); diff --git a/utils/filterFormData.ts b/utils/filterFormData.ts new file mode 100644 index 0000000..7a74d1d --- /dev/null +++ b/utils/filterFormData.ts @@ -0,0 +1,41 @@ +// If your project is using TypeScript, specify types accordingly +type AnyObj = { [key: string]: any }; + +export function filterFormData(data: AnyObj): AnyObj { + + if (data === null || data === undefined || Object.keys(data).length === 0) { + return {}; // Return an empty object or some default value as appropriate + } + if (!data.confirmed) { + return data; // Return the original data unmodified if not confirmed + } + //console.log("data", data) + const filterObject = (obj: AnyObj): AnyObj => { + const result: AnyObj = {}; + Object.entries(obj).forEach(([key, value]: [string, any]) => { + if (key === 'agendaItems') { + result[key] = value.filter((item: any) => item.status !== 'resolved').map((agendaItem: any) => { + if (agendaItem.actionItems) { + agendaItem.actionItems = agendaItem.actionItems.filter((actionItem: any) => actionItem.status !== 'done'); + } + return agendaItem; + }); + } else if (typeof value === 'object' && value !== null && !Array.isArray(value)) { + const filteredChild = filterObject(value); + if (Object.keys(filteredChild).length > 0) { + result[key] = filteredChild; + } + } else if (Array.isArray(value)) { + const filteredArray = value.filter(item => item && Object.keys(item).length > 0).map(item => typeof item === 'object' ? filterObject(item) : item); + if (filteredArray.length > 0) { + result[key] = filteredArray; + } + } else if (value || value === false) { + result[key] = value; + } + }); + return result; + }; + + return filterObject(data); +} diff --git a/utils/getMissingSummaries.js b/utils/getMissingSummaries.js index 77497fc..ca9fc31 100644 --- a/utils/getMissingSummaries.js +++ b/utils/getMissingSummaries.js @@ -1,17 +1,15 @@ import { supabase } from "../lib/supabaseClient"; function formatDate(dateString) { - const options = { year: 'numeric', month: 'long', day: 'numeric' }; const date = new Date(dateString); - // Manually construct the date string to ensure it's in "DD MMMM YYYY" format const formattedDate = `${date.getDate()} ${date.toLocaleString('en-US', { month: 'long' })} ${date.getFullYear()}`; return formattedDate; } export async function getMissingSummaries() { let missingSummaries = []; - let allDoneSummaries = []; - + let allSummaries = []; // Will include both done and archived summaries with adjustments + async function getAllMissingSummaries() { try { const { data, error, status } = await supabase @@ -31,31 +29,57 @@ export async function getMissingSummaries() { console.log("error", error.message); } } - + async function getAllSummaries() { - try { - const { data, error, status } = await supabase - .from('meetingsummaries') - .select('date, summary') - .order('date', { ascending: false }); - - if (error && status !== 406) throw error; - if (data) { - allDoneSummaries = data.map(item => ({ - meetingDate: formatDate(item.date), - status: "Done", // Setting status to "Done" for all done summaries - workgroup: item.summary.workgroup - })); + try { + const { data, error, status } = await supabase + .from('meetingsummaries') + .select('date, summary, confirmed, workgroup_id, updated_at') + .order('date', { ascending: false }); + + if (error && status !== 406) throw error; + + if (data) { + const summariesMap = new Map(); + + data.forEach(item => { + const key = `${item.date}-${item.workgroup_id}`; + const summary = { + meetingDate: formatDate(item.date), + status: item.confirmed ? "Archived" : "Done", + workgroup: item.summary.workgroup, // Assuming 'summary' has a 'workgroup' property + workgroupId: item.workgroup_id, + updated_at: item.updated_at, + confirmed: item.confirmed + }; + + if (!summariesMap.has(key)) { + summariesMap.set(key, [summary]); + } else { + summariesMap.get(key).push(summary); + } + }); + + summariesMap.forEach((value, key) => { + // Sort summaries by confirmed status first, then by updated_at descending + const sortedSummaries = value.sort((a, b) => b.confirmed - a.confirmed || new Date(b.updated_at) - new Date(a.updated_at)); + const actualSummary = sortedSummaries[0]; // Get the first summary after sorting + + // Remove unnecessary properties for the final result + delete actualSummary.updated_at; + delete actualSummary.confirmed; + + allSummaries.push(actualSummary); + }); + } + } catch (error) { + console.log("error", error.message); } - } catch (error) { - console.log("error", error.message); - } } - + await getAllMissingSummaries(); await getAllSummaries(); - - const combinedSummaries = [...missingSummaries, ...allDoneSummaries]; + const combinedSummaries = [...missingSummaries, ...allSummaries]; const uniqueSummariesMap = new Map(); combinedSummaries.forEach(summary => { @@ -64,7 +88,7 @@ export async function getMissingSummaries() { if (uniqueSummariesMap.has(key)) { // Prioritize "Done" summaries over "Missing" const existingSummary = uniqueSummariesMap.get(key); - if (existingSummary.status !== "Done" && summary.status === "Done") { + if ((existingSummary.status !== "Done" && summary.status === "Done") || (existingSummary.status !== "Archived" && summary.status === "Archived")) { uniqueSummariesMap.set(key, summary); } } else { @@ -72,7 +96,11 @@ export async function getMissingSummaries() { } }); - const finalSummaries = Array.from(uniqueSummariesMap.values()); - - return finalSummaries; - } \ No newline at end of file + const allFinalSummaries = Array.from(uniqueSummariesMap.values()); + // Since allSummaries now already includes the logic for both "Done" and "Archived" statuses + // and ensures that only actual summaries are included, we directly use it + const finalSummaries = allFinalSummaries.filter(summary => summary.status !== "Archived"); + const allArchivedSummaries = allSummaries.filter(summary => summary.status === "Archived"); + + return { finalSummaries, allArchivedSummaries }; +} diff --git a/utils/getsummaries.js b/utils/getsummaries.js index a21266e..f755f06 100644 --- a/utils/getsummaries.js +++ b/utils/getsummaries.js @@ -22,9 +22,8 @@ import { supabase } from "../lib/supabaseClient"; export async function getSummaries(workgroup_id) { let summaries = []; // Initialize an array to hold the summaries let summary = {}; - let lastConfirmedDate = null; - let lastUpdatedAt = null; let lastConfirmedMeeting = null; + let confirmedDates = new Set(); async function getMeetingSummaries() { try { @@ -41,17 +40,19 @@ export async function getSummaries(workgroup_id) { if (summaryData) { // Find the last confirmed meeting lastConfirmedMeeting = summaryData.find(data => data.confirmed === true); - if (lastConfirmedMeeting) { - lastConfirmedDate = lastConfirmedMeeting.date; - lastUpdatedAt = lastConfirmedMeeting.updated_at; - } + summaryData.forEach(data => { + if (data.confirmed) confirmedDates.add(data.date); + }); // Fetch the user details for each summary for (const data of summaryData) { - // Exclude meetings where confirmed == true and all meetings with an earlier date and updated_at date than the last meeting where confirmed == true - /*if (data.confirmed === true || new Date(data.date) < new Date(lastConfirmedDate)) { //Might have to add this back in later - || new Date(data.updated_at) < new Date(lastUpdatedAt) + const isSameDateAsLastConfirmed = lastConfirmedMeeting && new Date(data.date).getTime() === new Date(lastConfirmedMeeting.date).getTime(); + const isDateWithOtherConfirmed = confirmedDates.has(data.date) && (!lastConfirmedMeeting || (lastConfirmedMeeting && !isSameDateAsLastConfirmed)); + + // Skip if it's not the last confirmed and it's a date with another confirmed summary + if (data.confirmed && !isSameDateAsLastConfirmed || isDateWithOtherConfirmed) { continue; - }*/ + } const { data: userData, error: userError } = await supabase .from('users')