Skip to content
Merged
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
59 changes: 58 additions & 1 deletion components/SummaryTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { saveCustomAgenda } from '../utils/saveCustomAgenda';
import { generateMarkdown } from '../utils/generateMarkdown';
import axios from "axios";
import { filterFormData } from '../utils/filterFormData';
import { getQuarterOptions, generateQuarterlyReport } from '../utils/quarterlyReportGenerator';

type SummaryTemplateProps = {
updateMeetings: (newMeetingSummary: any) => void;
Expand Down Expand Up @@ -71,6 +72,9 @@ const SummaryTemplate = ({ updateMeetings }: SummaryTemplateProps) => {
const { myVariable, setMyVariable } = useMyVariable();
const [creatingDoc, setCreatingDoc] = useState<boolean>(false);
const today = new Date().toISOString().split('T')[0];
const [selectedQuarter, setSelectedQuarter] = useState('');
const [creatingQuarterlyDoc, setCreatingQuarterlyDoc] = useState(false);
const quarterOptions = getQuarterOptions();

const defaultFormData = {
workgroup: "",
Expand Down Expand Up @@ -120,11 +124,38 @@ const SummaryTemplate = ({ updateMeetings }: SummaryTemplateProps) => {
const [tags, setTags] = useState({ topicsCovered: "", emotions: "", other: "", gamesPlayed: "" });
const currentOrder = myVariable.agendaItemOrder ? myVariable.agendaItemOrder[myVariable.workgroup?.workgroup] : undefined;

async function handleCreateQuarterlyDoc() {
setCreatingQuarterlyDoc(true);

try {
const [quarter, year] = selectedQuarter.split(' ');
const quarterNumber = parseInt(quarter.slice(1));
const markdown = await generateQuarterlyReport(myVariable.workgroup.workgroup_id, parseInt(year), quarterNumber, currentOrder);
//console.log(markdown);
const response = await axios.post('/api/createGoogleDoc', {
markdown,
workgroup: myVariable.workgroup.workgroup,
date: selectedQuarter
});

window.open(response.data.link, '_blank');
} catch (error) {
console.error('Error creating Quarterly Google Doc:', error);
alert('There was an error creating the Quarterly Google Doc.');
} finally {
setCreatingQuarterlyDoc(false);
}
}

async function handleCreateGoogleDoc() {
setCreatingDoc(true); // Set creatingDoc to true when the button is clicked

try {
const markdown = generateMarkdown(myVariable.summary, currentOrder);
let markdown = generateMarkdown(myVariable.summary, currentOrder);

// Add a heading to the first line of the markdown
const heading = `# Meeting Summary for ${formData.workgroup}\nDate: ${formatTimestampForPdf(formData.meetingInfo?.date)}`;
markdown = `${heading}\n\n${markdown}`;
//console.log("markdown", markdown);
const response = await axios.post('/api/createGoogleDoc', {
markdown,
Expand Down Expand Up @@ -301,6 +332,32 @@ const SummaryTemplate = ({ updateMeetings }: SummaryTemplateProps) => {
<p className={styles.popupInfo}>
(The document will open in a new tab if popups are enabled for this site)
</p>
<div className={styles['quarterly-report-section']}>
<select
value={selectedQuarter}
onChange={(e) => setSelectedQuarter(e.target.value)}
className={styles.quarterSelect}
>
<option value="">Select Quarter</option>
{quarterOptions.map((option) => (
<option key={option} value={option}>
{option}
</option>
))}
</select>
<button
type="button"
onClick={handleCreateQuarterlyDoc}
className={styles.exportButton}
disabled={creatingQuarterlyDoc || !selectedQuarter}
>
{creatingQuarterlyDoc ? (
<span className={styles.flashingText}>Creating Quarterly Doc...</span>
) : (
"Create Quarterly Google Doc"
)}
</button>
</div>
</div>
</div>)}
</>
Expand Down
43 changes: 41 additions & 2 deletions pages/api/createGoogleDoc.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,26 @@ import { google } from 'googleapis';
import { JWT } from 'google-auth-library';
import { parseMarkdown } from '../../utils/markdownToGoogleDocs';

async function createFolderIfNotExists(drive, name, parentId) {
const query = `name='${name}' and mimeType='application/vnd.google-apps.folder' and '${parentId}' in parents`;
const response = await drive.files.list({ q: query, fields: 'files(id, name)' });

if (response.data.files.length > 0) {
return response.data.files[0].id;
} else {
const fileMetadata = {
name: name,
mimeType: 'application/vnd.google-apps.folder',
parents: [parentId]
};
const folder = await drive.files.create({
resource: fileMetadata,
fields: 'id'
});
return folder.data.id;
}
}

export default async function handler(req, res) {
if (req.method !== 'POST') {
return res.status(405).json({ message: 'Method not allowed' });
Expand All @@ -22,12 +42,31 @@ export default async function handler(req, res) {
const drive = google.drive({ version: 'v3', auth: jwtClient });
const docs = google.docs({ version: 'v1', auth: jwtClient });

const folderId = process.env.GOOGLE_DRIVE_FOLDER_ID;
const baseFolderId = process.env.GOOGLE_DRIVE_FOLDER_ID;

// Create folder structure
let year, month, parentFolderId;

if (date.includes('Q')) {
// Handle quarterly date format (e.g., "Q3 2024")
year = date.split(' ')[1];
const workgroupFolderId = await createFolderIfNotExists(drive, workgroup, baseFolderId);
parentFolderId = await createFolderIfNotExists(drive, year, workgroupFolderId);
} else {
// Handle regular date format
const dateObj = new Date(date);
year = dateObj.getFullYear().toString();
month = (dateObj.getMonth() + 1).toString().padStart(2, '0');

const workgroupFolderId = await createFolderIfNotExists(drive, workgroup, baseFolderId);
const yearFolderId = await createFolderIfNotExists(drive, year, workgroupFolderId);
parentFolderId = await createFolderIfNotExists(drive, month, yearFolderId);
}

const fileMetadata = {
name: `Meeting Summary - ${workgroup} - ${date}`,
mimeType: 'application/vnd.google-apps.document',
parents: [folderId]
parents: [parentFolderId]
};
const file = await drive.files.create({
resource: fileMetadata,
Expand Down
27 changes: 27 additions & 0 deletions styles/summarytemplate.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,31 @@
margin-top: 0.5rem;
font-size: 0.9rem;
color: #555;
}

.quarterly-report-section {
margin-top: 2rem;
display: flex;
flex-direction: column;
gap: 1rem;
}

.quarterSelect {
padding: 0.5rem;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 1rem;
width: 100%;
background-color: white;
cursor: pointer;
}

.quarterly-report-section .exportButton {
margin-top: 0;
}

.quarterly-report-section .exportButton:disabled {
background-color: #e0e0e0;
color: #a0a0a0;
cursor: not-allowed;
}
24 changes: 0 additions & 24 deletions utils/markdownToGoogleDocs.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,6 @@ export function parseMarkdown(markdown, workgroup, date) {
const requests = [];
let currentIndex = 1;

// Add header text
const headerText = `Meeting Summary for ${workgroup}\nDate: ${date}\n\n`;
requests.push({
insertText: {
location: { index: currentIndex },
text: headerText,
},
});
currentIndex += headerText.length;

// Apply heading style to the title
requests.push({
updateParagraphStyle: {
range: {
startIndex: 1,
endIndex: headerText.indexOf('\n') + 1,
},
paragraphStyle: {
namedStyleType: 'HEADING_1',
},
fields: 'namedStyleType',
},
});

const lines = markdown.split('\n');
let listLevel = 0; // Keeping this for possible indentation handling

Expand Down
80 changes: 80 additions & 0 deletions utils/quarterlyReportGenerator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// utils/quarterlyReportGenerator.js
import { supabase } from "../lib/supabaseClient";
import { generateMarkdown } from './generateMarkdown';

function formatTimestampForPdf(timestamp) {
// Create a Date object using the timestamp
const date = new Date(timestamp);

date.setHours(date.getHours() + 2);

const day = date.getUTCDate();
const month = date.toLocaleString('en-US', { month: 'long', timeZone: 'UTC' });
const year = date.getUTCFullYear();

return `${day} ${month} ${year}`;
}

export async function generateQuarterlyReport(workgroup_id, year, quarter, currentOrder) {
try {
// Define the start and end dates for the quarter
const startDate = new Date(Date.UTC(year, (quarter - 1) * 3, 1));
const endDate = new Date(Date.UTC(year, quarter * 3, 0, 23, 59, 59, 999));

//console.log('Fetching summaries for:', workgroup_id, 'Quarter:', quarter, 'Year:', year);
//console.log('Date range:', startDate.toISOString(), 'to', endDate.toISOString());

// Fetch all confirmed summaries for the workgroup
const { data: allSummaries, error } = await supabase
.from('meetingsummaries')
.select('*')
.eq('workgroup_id', workgroup_id)
.eq('confirmed', true)
.order('date', { ascending: true });

if (error) {
console.error('Error fetching summaries:', error);
throw error;
}

//console.log('Fetched all summaries:', allSummaries.length);

// Filter summaries for the specific quarter
const summaries = allSummaries.filter(summary => {
const summaryDate = new Date(summary.date);
return summaryDate >= startDate && summaryDate <= endDate;
});

//console.log('Filtered summaries for the quarter:', summaries);

if (summaries.length === 0) {
return `# No confirmed summaries found for Q${quarter} ${year}\n\nThere were no confirmed meeting summaries for this quarter.`;
}

// Generate markdown for each summary
let markdownContent = `# Quarterly Summaries for ${summaries[0]?.summary.workgroup || 'Workgroup'} - Q${quarter} ${year}\n\n`;

for (const summary of summaries) {
markdownContent += `## Summary for ${formatTimestampForPdf(summary.date)}\n\n`;
markdownContent += generateMarkdown(summary.summary, currentOrder) + '\n\n';
}

return markdownContent;
} catch (error) {
console.error('Error in generateQuarterlyReport:', error);
throw error;
}
}

export function getQuarterOptions() {
const currentYear = new Date().getFullYear();
const options = [];

for (let year = currentYear; year >= currentYear - 2; year--) {
for (let quarter = 4; quarter >= 1; quarter--) {
options.push(`Q${quarter} ${year}`);
}
}

return options;
}