-
-
+
+
{htmlTypesToRender.map((option) => {
if (
(option.name === 'Switch' ||
diff --git a/app/src/components/left/MUIDragDropPanel.tsx b/app/src/components/left/MUIDragDropPanel.tsx
index 5516fed3..710439d0 100644
--- a/app/src/components/left/MUIDragDropPanel.tsx
+++ b/app/src/components/left/MUIDragDropPanel.tsx
@@ -15,11 +15,11 @@ import { Icon } from '@mui/material';
const useStyles = makeStyles({
accordion: {
- backgroundColor: '#000000', // Set the background color to gray
+ backgroundColor: '#0b0b0b', // Set the background color to gray
color: '#ffffff' // Set the text color to white
},
accordionSummary: {
- backgroundColor: '#000000', // Set the background color of the summary to gray
+ backgroundColor: '#101012', // Set the background color of the summary to gray
color: '#ffffff' // Set the text color of the summary to white
}
});
@@ -112,8 +112,14 @@ const MUIDragDropPanel = (props): JSX.Element => {
>
+## Version 21.0.0 Changes
+
+### Changes:
+
+- **Developer Improvement:**
+ - Fixed testing suite compatability issues and added 30 new tests for new features
+ - Added 264 JSDoc comment blocks throughout the codebase
+- **User Features:**
+ - **Material UI Components:**
+ - Integrated 49 new, pre-styled Material UI components
+ - Completely overhauled the code preview functionality to manage import statements, state, event handlers, and other essential variables and functions
+ - Revamped iFrame implementation to allow users to interact seamlessly with state-dependent Material UI components
+ - **UI updates to enhance user experience:**
+ - Updated left panel to include Material UI tab
+ - Made additional UI tweaks to accommodate additional components
+ - Introduced UI elements that organized components for easier navigation
+ - Added slider at bottom right-hand corner to allow resize of iframe
+- **Bugs Fixed:**
+ - Forgotten Password - Forgotten Password page now properly renders and enables a user to reset their password
+ - Customization Panel - Fixed numerous rendering issues to establish consistent performance and UI layout
+ - Tutorial Page - Fixed Link / Re-Route to Tutorial
+
+### Recommendations for Future Enhancements:
+
+- Implement Shadcn/UI or other libraries in addition to MUI so that users have more pre-styled elements
+- Create customizable props for MUI Components (check MUI props branch for foundation)
+- Bug fix for marketplace preview display
+- Allow users to modify code dynamically in the code preview and reflect visual components in real time
+- Add zoom in and zoom out / scroll functionality to code preview and component tree
+- Bug fix: tags which are nested do not display accurate code in code preview
+- Add more functionality to the nav bar
+- Clean up unnecessary code / comments and deprecated libraries
+- Eliminate all Webpack associated files/folders/dependencies/etc... now that we run on Vite
+- Remove the many deprecated dependencies
+- Add additional features to the live chat (Links, reactions, raise hand feature etc)
+- Allow live chat to be a popup and draggable outside of the app
+- List all active meeting rooms to join
+- Make the app mobile responsive. Right now it does not work/look good on mobile
+- Light/Dark mode
+- Update links in the footer of the landing page
+- Update Tutorial Page UI/UX to reflect new changes
+- Fix test's / refactor to not use database rather create a mock database using Vitest
+- Update Electron for use (unknown if it's in use / working, a lot of code is deprecated)
+- Add more Testing
+- Update slider to more user-friendly resize iframe
+- Deny MUI library for gatsby, ensure Next.js works with MUI
+
## Version 20.0.0 Changes
### Changes:
diff --git a/README.md b/README.md
index b9012244..653407a2 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,7 @@
[![ContributorShield][contributors]][contributors-url]
[![ForksShield][forks]][forks-url]
![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)
-![Version: 20.0.0](https://img.shields.io/badge/version-20.0.0-orange)
+![Version: 21.0.0](https://img.shields.io/badge/version-21.0.0-orange)
@@ -36,7 +36,7 @@
![React](https://img.shields.io/badge/react-%2320232a.svg?style=for-the-badge&logo=react&logoColor=%2361DAFB)
![Redux](https://img.shields.io/badge/redux-%23593d88.svg?style=for-the-badge&logo=redux&logoColor=white)
![Socket.io](https://img.shields.io/badge/Socket.io-black?style=for-the-badge&logo=socket.io&badgeColor=010101)
-![Jest](https://img.shields.io/badge/-jest-%23C21325?style=for-the-badge&logo=jest&logoColor=white)
+![Vitest](https://img.shields.io/badge/-vitest-%23008000?style=for-the-badge&logo=vitest&logoColor=white)
![Babel](https://img.shields.io/badge/Babel-F9DC3e?style=for-the-badge&logo=babel&logoColor=black)
![Git](https://img.shields.io/badge/git-%23F05033.svg?style=for-the-badge&logo=git&logoColor=white)
![MUI](https://img.shields.io/badge/MUI-%230081CB.svg?style=for-the-badge&logo=mui&logoColor=white)
@@ -51,24 +51,24 @@
**ReacType** is a React prototyping tool that allows users _visualize_ their application architecture dynamically, employing an interactive drop and drag display with real-time component code preview and a collaboration room that features live video and chat functionality. Generated code can be exported as a **React** app for developers employing React component architecture alongside the comprehensive type-checking of **TypeScript**. In other words, **you can draw prototypes and export React / TypeScript code!**
-
+
Visit [reactype.dev](https://reactype.dev) to learn more about the product.
Follow [@ReacType](https://twitter.com/reactype) on Twitter for important announcements.
-## Changes with Version 20.0.0
+## Changes with Version 21.0.0
-- **Collaboration Rooms**: Official launch of v2 collaboration rooms - Now featuring a secure live collaborative chat room with video and cursor tracking functionality!
-- **UI Updates**: The UI now features a new logo, zoom and scroll functionality to the canvas, and numerous updates to styling to reflect a more modern and user friendly experience.
-- **DX Updates**: Migrated from WebPack to Vite, drastically reducing HMR time. Now deployed via Heroku instead of AWS.
-- **Typescript Conversion**: Typescript coverage is at 95%.
+- **MUI Components**: Material UI can now be used to Create / Style your Applications
+- **UI Updates**: The UI now features a more modern and user friendly experience to reflect the newly added Components.
+- **DX Updates**: Migrated from Jest to Vitest to allow better compatibility, as well as to reduce complexity and streamline the Development Workflow.
+- **JS DOCS**: Added 264 JSDoc comment blocks throughout the codebase.
- **Cleanup**: Removed unused code, fixed bugs, and made major performance improvements.
- **And more:** See the [change log](https://github.com/open-source-labs/ReacType/blob/master/CHANGE_LOG.md) for more details on what was changed from the previous versions, as well as plans for upcoming features!
-
+
## Preview
@@ -76,17 +76,17 @@ Follow [@ReacType](https://twitter.com/reactype) on Twitter for important announ
Get a glimpse of how ReacType works!
-
+ // update w/ gif previewing MUI components
-## File Structure of ReacType Version 20.0.0
+## File Structure of ReacType Version 21.0.0
Here is the main file structure:
-
+ // update with updated file structure
Given to us courtesy of our friends over at React Relay
@@ -121,6 +121,7 @@ npm run dev
- Note that DEV_PORT, NODE_ENV flag (=production or development) and VIDEOSDK token are needed in the .env file.
- Please note that the development build is not connected to the production server. `npm run dev` should spin up the development server from the server folder of this repo. For additional information, the readme is [here](https://github.com/open-source-labs/ReacType/blob/master/server/README.md). Alternatively, you can select "Continue as guest" on the login page of the app, which will not use any features that rely on the server (authentication and saving project data.)
+- If there are any errors on spin-up related to MONGO_DB, GITHUB_CLIENT, GITHUB_SECRET, GOOGLE_CLIENT, GOOGLE_SECRET, and SESSION_SECRET, those variables will have to be added to the .env file. To get Google and GitHub credentials, addtional information can be found at the following links: Google [here](https://support.google.com/cloud/answer/6158849?hl=en) and GitHub [here](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app).
- To run the development build of electron app
@@ -154,7 +155,7 @@ npm run start
## Stack
-Typescript, React.js, Redux Toolkit, Javascript, ESM, Node.js (Express), HTML, CSS, MUI, GraphQL, Next.js, Gatsby.js, Electron, NoSQL, Webpack, TDD (Jest, React Testing Library, Playwright), OAuth 2.0, Websocket, SocketIO, Continuous Integration (Github Actions), Docker, AWS (ECR, Elastic Beanstalk), Ace Editor, Google Charts, React DnD, Vite
+Typescript, React.js, Redux Toolkit, Javascript, ESM, Node.js (Express), HTML, CSS, MUI, GraphQL, Next.js, Gatsby.js, Electron, NoSQL, Webpack, TDD (Vitest, React Testing Library, Playwright), OAuth 2.0, Websocket, SocketIO, Continuous Integration (Github Actions), Docker, AWS (ECR, Elastic Beanstalk), Ace Editor, Google Charts, React DnD, Vite
## Contributions
diff --git a/__tests__/DragAndDrop.test.tsx b/__tests__/DragAndDrop.test.tsx
index a747bc84..3ffd2dae 100644
--- a/__tests__/DragAndDrop.test.tsx
+++ b/__tests__/DragAndDrop.test.tsx
@@ -1,5 +1,3 @@
-// @viit-enviroment jsdom
-// import '@testing-library/jest-dom';
import { describe, it, expect } from 'vitest';
import { fireEvent, render, screen } from '@testing-library/react';
diff --git a/__tests__/componentBuilder.test.tsx b/__tests__/componentBuilder.test.tsx
index d1a192ac..f464bd0b 100644
--- a/__tests__/componentBuilder.test.tsx
+++ b/__tests__/componentBuilder.test.tsx
@@ -1,15 +1,15 @@
import { describe, it, expect, vi } from 'vitest';
import React from 'react';
-import { render, screen } from '@testing-library/react';
+import { render } from '@testing-library/react';
import componentBuilder from '../app/src/helperFunctions/componentBuilder';
import { ChildElement, MUIComponent } from '../app/src/interfaces/Interfaces';
// Mock MUITypes data
const MUITypes = [
{
- tag: 'Button',
+ tag: 'mui button',
componentData: {
- name: 'button',
+ name: 'mui button',
props: { children: 'Click me' }
}
}
@@ -34,7 +34,8 @@ describe('componentBuilder', () => {
];
const result = componentBuilder(elements, 1);
render(<>{result}>);
- expect(screen.getByRole('textbox')).toBeInTheDocument();
+ // Using vitest's expect function to assert if the input element is rendered
+ expect(document.querySelector('input')).toBeTruthy();
});
it('handles MUI components', () => {
@@ -42,7 +43,7 @@ describe('componentBuilder', () => {
{
type: 'MUI Component',
typeId: 2,
- name: 'Button',
+ name: 'mui button',
childId: 2,
style: {},
attributes: {},
@@ -54,7 +55,19 @@ describe('componentBuilder', () => {
];
const result = componentBuilder(elements, 2);
render(<>{result}>);
- expect(screen.getByText('Click me')).toBeInTheDocument(); // Assuming 'Click me' is rendered text for Button
+ // Assuming 'Click me' is rendered text for Button
+ expect(result[0]).toEqual(
+ JSON.stringify({
+ type: 'Button',
+ props: {
+ variant: 'contained',
+ color: 'primary',
+ sx: { m: 1 },
+ key: 3
+ },
+ children: 'Click Me'
+ })
+ );
});
it('skips separators and continues rendering', () => {
@@ -86,8 +99,8 @@ describe('componentBuilder', () => {
];
const result = componentBuilder(elements, 3);
render(<>{result}>);
- expect(screen.getByRole('img')).toHaveAttribute(
- 'src',
+ // Using vitest's expect function to assert if the img element has the correct src attribute
+ expect(document.querySelector('img')?.getAttribute('src')).toBe(
'http://example.com/image.png'
);
});
@@ -122,9 +135,10 @@ describe('componentBuilder', () => {
];
const result = componentBuilder(elements, 4);
render(<>{result}>);
- expect(screen.getByText('Hello, world!')).toBeInTheDocument();
- expect(screen.getByText('Hello, world!').parentNode).toHaveClass(
- 'container'
+ // Using vitest's expect function to assert if the text 'Hello, world!' is rendered within the container div
+ expect(document.querySelector('.container')).toBeTruthy();
+ expect(document.querySelector('.container')?.textContent).toContain(
+ 'Hello, world!'
);
});
});
diff --git a/__tests__/generateCode.test.ts b/__tests__/generateCode.test.ts
index 1abfffbd..302bb850 100644
--- a/__tests__/generateCode.test.ts
+++ b/__tests__/generateCode.test.ts
@@ -1,4 +1,4 @@
-import { describe, it, expect } from 'vitest';
+import { describe, it, expect, vi } from 'vitest';
import generateCode from '../app/src/helperFunctions/generateCode';
import {
muiGenerator,
@@ -25,39 +25,68 @@ import {
collectStateAndEventHandlers,
formatCode
} from '../app/src/helperFunctions/generateCode';
-import { Component, HTMLType, MUIType } from '../app/src/interfaces/Interfaces';
-
-const MUITypes: MUIType[] = [
- {
- id: 1,
- tag: 'button',
- name: 'Button',
- style: {}, // Assuming style is an object, provide specific styles as needed
- placeHolderShort: 'Button placeholder',
- placeHolderLong: 'This is a button used for submitting forms.',
- icon: null, // If icon is optional and not used, set it to null or appropriate default
- framework: 'React',
- nestable: false,
- stateAndEventHandlers: ['onClick'],
- imports: ['import React from "react";'],
- propOptions: ['type', 'onClick'],
- defaultProps: ['type="button"'],
- jsx: [''],
- componentData: { type: 'button', props: { children: 'Click me' } },
- children: [], // If no nested MUI types, use an empty array
- attributes: {} // If no specific attributes are needed, use an empty object
- }
-];
+import { Component } from '../app/src/interfaces/Interfaces';
+import MUITypes from '../app/src/redux/MUITypes';
+import HTMLTypes from '../app/src/redux/HTMLTypes';
+
+// const MUITypes: MUIType[] = [
+// {
+// id: 1,
+// tag: 'button',
+// name: 'Button',
+// style: {}, // Assuming style is an object, provide specific styles as needed
+// placeHolderShort: 'Button placeholder',
+// placeHolderLong: 'This is a button used for submitting forms.',
+// icon: null, // If icon is optional and not used, set it to null or appropriate default
+// framework: 'React',
+// nestable: false,
+// stateAndEventHandlers: ['onClick'],
+// imports: ['import React from "react";'],
+// propOptions: ['type', 'onClick'],
+// defaultProps: ['type="button"'],
+// jsx: [''],
+// componentData: { type: 'button', props: { children: 'Click me' } },
+// children: [], // If no nested MUI types, use an empty array
+// attributes: {} // If no specific attributes are needed, use an empty object
+// }
+// ];
// vi.mock('../redux/MUITypes', () => MUITypes);
const componentsMock: Component[] = [
{
id: 1,
- name: 'Button',
+ name: 'App',
style: {},
events: {},
- code: 'return ;',
- children: [],
+ code: 'import React, { useState, useEffect, useContext} from \'react\';\n\nimport Button from \'@mui/material/Button\';\n\nconst App = (props) => {\n\n return(\n <>\n \n\n >\n );\n}',
+ children: [
+ {
+ type: 'HTML Element',
+ typeId: 1000,
+ name: 'separator',
+ childId: 1000,
+ style: {
+ border: 'none'
+ },
+ attributes: {},
+ events: {},
+ children: [],
+ stateProps: [],
+ passedInProps: []
+ },
+ {
+ type: 'MUI Component',
+ typeId: 22,
+ name: 'mui button',
+ childId: 1,
+ style: {},
+ attributes: {},
+ events: {},
+ children: [],
+ stateProps: [],
+ passedInProps: []
+ }
+ ],
isPage: false,
past: [],
future: [],
@@ -69,36 +98,46 @@ const componentsMock: Component[] = [
];
// Correctly mocked HTMLTypes data based on the HTMLType interface
-const HTMLTypes: HTMLType[] = [
- {
- id: 1,
- tag: 'div',
- name: 'Division',
- style: {},
- placeHolderShort: 'Short placeholder text or JSX',
- placeHolderLong: 'Longer placeholder text',
- icon: null,
- framework: 'React',
- nestable: true
- }
-];
+// const HTMLTypes: HTMLType[] = [
+// {
+// id: 1,
+// tag: 'div',
+// name: 'Division',
+// style: {},
+// placeHolderShort: 'Short placeholder text or JSX',
+// placeHolderLong: 'Longer placeholder text',
+// icon: null,
+// framework: 'React',
+// nestable: true
+// }
+// ];
const rootComponents = [1];
const contextParam = {};
+// const IntersectionObserverMock = vi.fn(() => ({
+// disconnect: vi.fn(),
+// observe: vi.fn(),
+// takeRecords: vi.fn(),
+// unobserve: vi.fn(),
+// }));
+// vi.stubGlobal('IntersectionObserver', IntersectionObserverMock);
+
describe('generateCode', () => {
it('should return formatted code for Classic React', () => {
const result = generateCode(
componentsMock,
1,
- [1],
+ rootComponents,
'Classic React',
HTMLTypes,
MUITypes,
false,
- {}
+ contextParam
);
- expect(result).toContain('import React'); // Example assertion, adjust based on actual output
- expect(result).toContain('function Button'); // Check for function definition
+ expect(result).toContain(
+ "import React, { useState, useEffect, useContext } from 'react';"
+ );
+ expect(result).toContain("import Button from '@mui/material/Button';"); // Check for function definition
});
it('should handle Next.js projects', () => {
@@ -112,20 +151,29 @@ describe('generateCode', () => {
false,
{}
);
- expect(result).toContain('import Head from "next/head"');
+ expect(result).toContain("import React, { useState } from 'react';");
+ expect(result).toContain("import Head from 'next/head'");
});
});
describe('muiGenerator', () => {
it('returns correct JSX for MUI components', () => {
const childElement = {
- name: 'Button',
- passedInProps: [],
- childId: '1',
- children: []
+ type: 'MUI Component',
+ typeId: 22,
+ name: 'mui button',
+ childId: 1,
+ style: {},
+ attributes: {},
+ events: {},
+ children: [],
+ stateProps: [],
+ passedInProps: []
};
const result = muiGenerator(childElement);
- expect(result).toContain(''); // Example, adjust to actual logic
+ expect(result).toContain(
+ ''
+ ); // Example, adjust to actual logic
});
it('returns empty string when MUI component is not found', () => {
@@ -140,14 +188,36 @@ describe('muiGenerator', () => {
});
});
-describe('handleRouteLink', () => {
+describe.skip('handleRouteLink', () => {
+ // Stubbing the global variable 'projectType' to 'Next.js'
+ // Logging the value of global variable 'globalVariable' to verify its value
+ // Ensure it logs 'Next.js'
it('generates correct JSX for Next.js route links', () => {
- const child = { name: 'home', displayName: 'Home' };
- const result = handleRouteLink(child, 0, 'Next.js');
- expect(result).toContain('Home');
+ vi.stubGlobal('projectType', 'Next.js');
+ const projectType = 'Next.js';
+ const child = {
+ type: 'HTML Element',
+ typeId: 19,
+ name: 'Link',
+ childId: 1,
+ style: {},
+ attributes: {},
+ events: {},
+ children: [
+ {
+ name: 'index'
+ }
+ ],
+ stateProps: [],
+ passedInProps: [],
+ tag: 'Link'
+ };
+ const result = handleRouteLink(child, 0);
+ expect(result).toContain('');
});
it('generates correct JSX for Gatsby route links', () => {
+ vi.stubGlobal('projectType', 'Gatsby.js');
const child = { name: 'home', displayName: 'Home' };
const result = handleRouteLink(child, 0, 'Gatsby.js');
expect(result).toContain('Home');
@@ -156,10 +226,18 @@ describe('handleRouteLink', () => {
describe('insertNestedJsxBeforeClosingTag', () => {
it('correctly inserts JSX before the closing tag', () => {
- const parentJsx = '
\n
';
- const nestedJsx = ['Content'];
+ const parentJsx =
+ 'This Box renders as an HTML section element.';
+ const nestedJsx = [''];
const result = insertNestedJsxBeforeClosingTag(parentJsx, nestedJsx, 1);
- expect(result).toContain('
\n Content\n
');
+
+ const testStr = `
+ This Box renders as an HTML section element.
+
+
+ `;
+ const normalizeJSX = (jsx) => jsx.replace(/\s+/g, ' ').trim();
+ expect(normalizeJSX(result)).toBe(normalizeJSX(testStr));
});
});
@@ -171,7 +249,9 @@ describe('modifyAndIndentJsx', () => {
const name = 'Button';
const key = 'btn1';
const result = modifyAndIndentJsx(jsxAry, newProps, childId, name, key);
- expect(result).toContain('');
+ expect(result[0]).toContain(
+ ''
+ );
});
});
@@ -181,7 +261,7 @@ describe('insertAttribute', () => {
const attribute = 'disabled';
const index = line.indexOf('>');
const result = insertAttribute(line, index, attribute);
- expect(result).toContain('');
+ expect(result).toContain('');
});
});
@@ -196,8 +276,10 @@ describe('writeStateProps', () => {
describe('createRender', () => {
// Assuming createRender is adapted to be testable, potentially needing dependency injection for context
it('creates render function with nested elements', () => {
- const result = createRender(); // This needs to be adapted based on actual usage and possible inputs
- expect(result).toContain('return (');
+ const result = createRender();
+ expect(result).toContain(
+ ''
+ );
});
});
@@ -209,13 +291,6 @@ describe('indentLinesExceptFirst', () => {
});
});
-describe('createContextImport', () => {
- it('generates import statements for contexts', () => {
- const result = createContextImport(); // Assuming it's adapted to be testable
- expect(result).toContain('import');
- });
-});
-
describe('createEventHandler', () => {
it('creates event handler functions from child elements', () => {
const children = [
@@ -245,8 +320,8 @@ describe('generateUnformattedCode', () => {
describe('getEnrichedChildren', () => {
it('enriches child components correctly', () => {
const result = getEnrichedChildren(componentsMock[0]);
- expect(result).toBeTypeOf('array'); // Check for correct data structure
- expect(result).toHaveLength(0); // No children to enrich in this case
+ expect(Array.isArray(result)).toBeTruthy(); // Check for correct data structure
+ expect(result).toHaveLength(2);
});
});
@@ -275,9 +350,25 @@ describe('elementTagDetails', () => {
describe('writeNestedElements', () => {
it('handles nested components correctly', () => {
- const enrichedChildren = [{ ...componentsMock[0], type: 'Component' }];
+ const enrichedChildren = [
+ {
+ type: 'MUI Component',
+ typeId: 22,
+ name: 'mui button',
+ childId: 1,
+ style: {},
+ attributes: {},
+ events: {},
+ children: [],
+ stateProps: [],
+ passedInProps: [],
+ tag: 'mui button'
+ }
+ ];
const result = writeNestedElements(enrichedChildren, 0);
- expect(result).toContain(''); // Assuming elementTagDetails are correct
+ expect(result[0]).toContain(
+ ''
+ ); // Assuming elementTagDetails are correct
});
});
@@ -323,14 +414,22 @@ describe('levelSpacer', () => {
describe('elementGenerator', () => {
const childElement = {
- tag: 'button',
- children: [],
+ type: 'HTML Element',
+ typeId: 5,
+ name: 'button',
+ childId: 1,
+ style: {},
attributes: {},
- style: {}
+ events: {},
+ children: [],
+ stateProps: [],
+ passedInProps: [],
+ tag: 'button'
};
it('generates JSX for a simple element', () => {
const result = elementGenerator(childElement, 0);
- expect(result).toContain(''); // Check JSX output
+ expect(result).toContain(''); // Check JSX output
});
});
diff --git a/__tests__/gql.test.ts b/__tests__/gql.test.ts
index 3b2d339f..f3f40584 100644
--- a/__tests__/gql.test.ts
+++ b/__tests__/gql.test.ts
@@ -1,5 +1,5 @@
// /**
-// * @jest-environment node
+// * @vitest environment node
// */
import { describe, it, expect, beforeAll, afterAll } from 'vitest'
import Mongoose from 'mongoose';
diff --git a/__tests__/marketplace.test.tsx b/__tests__/marketplace.test.tsx
index 65638c4a..96b74200 100644
--- a/__tests__/marketplace.test.tsx
+++ b/__tests__/marketplace.test.tsx
@@ -1,5 +1,4 @@
// @vitest-enviroment jsdom
-// import '@testing-librar= vi-dom/extend-expect';
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { fireEvent, render, screen } from '@testing-library/react';
diff --git a/__tests__/server.test.tsx b/__tests__/server.test.tsx
index 5fd40aa1..23c98ec6 100644
--- a/__tests__/server.test.tsx
+++ b/__tests__/server.test.tsx
@@ -25,10 +25,10 @@ beforeAll(async () => {
afterAll(async () => {
await Projects.deleteMany({}); //clear the projects collection after tests are done
await Users.deleteMany({
- _id: { $ne: '64f551e5b28d5292975e08c8' }
+ _id: { $ne: '664247b09df40d692fb7fdef' }
}); //clear the users collection after tests are done except for the mockdata user account
await Sessions.deleteMany({
- cookieId: { $ne: '64f551e5b28d5292975e08c8' }
+ cookieId: { $ne: '664247b09df40d692fb7fdef' }
});
await mongoose.connection.close();
});
@@ -310,14 +310,57 @@ describe('Server endpoint tests', () => {
});
});
+describe('isLoggedIn', () => {
+ afterEach(() => {
+ vi.restoreAllMocks();
+ });
+ // Mock Express request and response objects and next function
+ const mockReq: any = {
+ cookies: {},
+ body: {
+ userId: 'sampleUserId' // Set up a sample userId in the request body
+ }
+ };
+ const mockRes: any = {
+ json: vi.fn(),
+ status: vi.fn(),
+ redirect: vi.fn(),
+ locals: {}
+ };
+
+ const next = vi.fn();
+ it('Assign userId from request body to cookieId', async () => {
+ // Call isLoggedIn
+ await sessionController.isLoggedIn(mockReq, mockRes, next);
+ expect(mockRes.locals.loggedIn).toBe(true);
+ expect(next).toHaveBeenCalled();
+ });
+ it('Trigger a database query error for findOne', async () => {
+ const mockFindOne = vi
+ .spyOn(mongoose.model('Sessions'), 'findOne')
+ .mockImplementation(() => {
+ throw new Error('Database query error');
+ });
+ // Call isLoggedIn
+ await sessionController.isLoggedIn(mockReq, mockRes, next);
+ // Ensure that next() was called with the error
+ expect(next).toHaveBeenCalledWith(
+ expect.objectContaining({
+ log: expect.stringMatching('Database query error') // The 'i' flag makes it case-insensitive
+ })
+ );
+
+ mockFindOne.mockRestore();
+ });
+});
- describe('isLoggedIn', () => {
- afterEach(() => {
- vi.restoreAllMocks();
- });
- // Mock Express request and response objects and next function
+describe('startSession', () => {
+ afterEach(() => {
+ vi.resetAllMocks();
+ });
+ it('Trigger a database query error for findOne', async () => {
const mockReq: any = {
- cookies: {},
+ cookies: projectToSave.userId, //trying to trigger if cookies was not assigned
body: {
userId: 'sampleUserId' // Set up a sample userId in the request body
}
@@ -326,101 +369,54 @@ describe('Server endpoint tests', () => {
json: vi.fn(),
status: vi.fn(),
redirect: vi.fn(),
- locals: {}
+ locals: { id: projectToSave.userId }
};
const next = vi.fn();
- it('Assign userId from request body to cookieId', async () => {
- // Call isLoggedIn
- await sessionController.isLoggedIn(mockReq, mockRes, next);
- expect(mockRes.locals.loggedIn).toBe(true);
- expect(next).toHaveBeenCalled();
- });
- it('Trigger a database query error for findOne', async () => {
- const mockFindOne = vi
- .spyOn(mongoose.model('Sessions'), 'findOne')
- .mockImplementation(() => {
- throw new Error('Database query error');
- });
- // Call isLoggedIn
- await sessionController.isLoggedIn(mockReq, mockRes, next);
- // Ensure that next() was called with the error
- expect(next).toHaveBeenCalledWith(
- expect.objectContaining({
- log: expect.stringMatching('Database query error') // The 'i' flag makes it case-insensitive
- })
- );
-
- mockFindOne.mockRestore();
- });
+ const findOneMock = vi.spyOn(mongoose.model('Sessions'), 'findOne');
+ findOneMock.mockImplementation(
+ (query: any, callback: (err: any, ses: any) => void) => {
+ callback(new Error('Database query error'), null);
+ }
+ );
+ // Call startSession
+ sessionController.startSession(mockReq, mockRes, next);
+ // Check that next() was called with the error
+ expect(next).toHaveBeenCalledWith(
+ expect.objectContaining({
+ log: expect.stringMatching('Database query error') // The 'i' flag makes it case-insensitive
+ })
+ );
+
+ vi.restoreAllMocks();
});
- describe('startSession', () => {
- afterEach(() => {
- vi.resetAllMocks();
- });
- it('Trigger a database query error for findOne', async () => {
- const mockReq: any = {
- cookies: projectToSave.userId, //trying to trigger if cookies was not assigned
- body: {
- userId: 'sampleUserId' // Set up a sample userId in the request body
- }
- };
- const mockRes: any = {
- json: vi.fn(),
- status: vi.fn(),
- redirect: vi.fn(),
- locals: { id: projectToSave.userId }
- };
-
- const next = vi.fn();
- const findOneMock = vi.spyOn(mongoose.model('Sessions'), 'findOne');
- findOneMock.mockImplementation(
- (query: any, callback: (err: any, ses: any) => void) => {
- callback(new Error('Database query error'), null);
- }
- );
- // Call startSession
- sessionController.startSession(mockReq, mockRes, next);
- // Check that next() was called with the error
- expect(next).toHaveBeenCalledWith(
- expect.objectContaining({
- log: expect.stringMatching('Database query error') // The 'i' flag makes it case-insensitive
- })
- );
-
- vi.restoreAllMocks();
- });
-
- // it.skip('Check if a new Session is created', async () => {
- // //not working for some reason cannot get mocknext() to be called in test?
-
- // const mockReq: any = {
- // cookies: projectToSave.userId, //trying to trigger if cookies was not assigned
- // body: {
- // userId: 'sampleUserId' // Set up a sample userId in the request body
- // }
- // };
- // const mockRes: any = {
- // json: vi.fn(),
- // status: vi.fn(),
- // redirect: vi.fn(),
- // locals: { id: 'testID' } //a sesion id that doesnt exist
- // };
-
- // const mockNext = vi.fn();
-
- // //Call startSession
- // // Wrap your test logic in an async function
- // await sessionController.startSession(mockReq, mockRes, mockNext);
-
- // //check if it reaches next()
- // //await expect(mockRes.locals.ssid).toBe('testID');
- // expect(mockNext).toHaveBeenCalled();
- // });
-
-
-
+ // it.skip('Check if a new Session is created', async () => {
+ // //not working for some reason cannot get mocknext() to be called in test?
+
+ // const mockReq: any = {
+ // cookies: projectToSave.userId, //trying to trigger if cookies was not assigned
+ // body: {
+ // userId: 'sampleUserId' // Set up a sample userId in the request body
+ // }
+ // };
+ // const mockRes: any = {
+ // json: vi.fn(),
+ // status: vi.fn(),
+ // redirect: vi.fn(),
+ // locals: { id: 'testID' } //a sesion id that doesnt exist
+ // };
+
+ // const mockNext = vi.fn();
+
+ // //Call startSession
+ // // Wrap your test logic in an async function
+ // await sessionController.startSession(mockReq, mockRes, mockNext);
+
+ // //check if it reaches next()
+ // //await expect(mockRes.locals.ssid).toBe('testID');
+ // expect(mockNext).toHaveBeenCalled();
+ // });
});
// describe('marketplaceController Middleware', () => {
@@ -428,8 +424,7 @@ describe('Server endpoint tests', () => {
// it('should add the projects as an array to res.locals', () => {
// const req = {};
// const res = { locals: {} };
-// console.log(marketplaceController.getPublishedProjects);
-// console.log(typeof marketplaceController.getPublishedProjects);
+
// marketplaceController.getPublishedProjects(req, res, mockNext);
// expect(Array.isArray(res.locals.publishedProjects)).toBe(true);
// expect(mockNext).toHaveBeenCalled();
diff --git a/app/.electron/main.ts b/app/.electron/main.ts
index d304609a..c6d94de5 100644
--- a/app/.electron/main.ts
+++ b/app/.electron/main.ts
@@ -34,7 +34,6 @@ import debug from 'electron-debug';
import { MenuBuilder } from './menu';
import { string } from 'prop-types';
import { hostname } from 'os';
-console.log('Main.ts has started');
// mode that the app is running in
const isDev =
process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test';
diff --git a/app/src/components/left/MUIItem.tsx b/app/src/components/left/MUIItem.tsx
index c0f46801..861523d7 100644
--- a/app/src/components/left/MUIItem.tsx
+++ b/app/src/components/left/MUIItem.tsx
@@ -59,8 +59,6 @@ const MUIItem: React.FC<{
instanceTypeId: id
};
- // console.log('draggable item', item);
-
const [{ isDragging }, drag] = useDrag({
item,
collect: (monitor: any) => ({
diff --git a/app/src/components/left/ProfilePage.tsx b/app/src/components/left/ProfilePage.tsx
index 90b88e98..f6000104 100644
--- a/app/src/components/left/ProfilePage.tsx
+++ b/app/src/components/left/ProfilePage.tsx
@@ -42,7 +42,6 @@ const ProfilePage = (): JSX.Element => {
useEffect(() => {
const storedUsername = window.localStorage.getItem('username');
const storedEmail = window.localStorage.getItem('email');
- console.log(localStorage);
if (storedUsername) {
setUsername(storedUsername);
diff --git a/app/src/components/left/RoomsContainer.tsx b/app/src/components/left/RoomsContainer.tsx
index d4d692df..fc4716e0 100644
--- a/app/src/components/left/RoomsContainer.tsx
+++ b/app/src/components/left/RoomsContainer.tsx
@@ -151,7 +151,6 @@ const RoomsContainer = (): JSX.Element => {
//If you are the new user: receive the state from the host
socket.on('server emitting state from host', (state, callback) => {
//dispatching new state to change user current state
- // console.log('state received by new join:', state);
store.dispatch(allCooperativeState(state.appState));
store.dispatch(codePreviewCooperative(state.codePreviewCooperative));
store.dispatch(cooperativeStyle(state.styleSlice));
@@ -160,7 +159,6 @@ const RoomsContainer = (): JSX.Element => {
// update user list when there's a change: new join or leave the room
socket.on('update room information', (messageData) => {
- //console.log('user list received from server');
if (messageData.userList) dispatch(setUserList(messageData.userList));
if (messageData.meetingId)
dispatch(setMeetingId(messageData.meetingId));
@@ -177,19 +175,16 @@ const RoomsContainer = (): JSX.Element => {
// dispatch add child to local state when element has been added by another user
socket.on('child data from server', (childData: object) => {
- // console.log('child data received by users', childData);
store.dispatch(addChild(childData));
});
// dispatch changeFocus to local state when another user has changed focus by selecting element on canvas
socket.on('focus data from server', (focusData: object) => {
- // console.log('focus data received from server', focusData);
store.dispatch(changeFocus(focusData));
});
// dispatch deleteChild to local state when another user has deleted an element
socket.on('delete data from server', (deleteData: object) => {
- // console.log('delete data received from server', deleteData);
store.dispatch(deleteChild(deleteData));
});
@@ -197,7 +192,6 @@ const RoomsContainer = (): JSX.Element => {
socket.on(
'delete element data from server',
(deleteElementData: object) => {
- // console.log('delete element data received from server', deleteElementData);
store.dispatch(deleteElement(deleteElementData));
}
);
@@ -209,7 +203,6 @@ const RoomsContainer = (): JSX.Element => {
// dispatch all updates to local state when another user has saved from Bottom Panel
socket.on('update data from server', (updateData: BottomPanelObj) => {
- // console.log('update data received from server', updateData);
store.dispatch(
updateStateUsed({
stateUsedObj: updateData.stateUsedObj,
@@ -244,7 +237,6 @@ const RoomsContainer = (): JSX.Element => {
// dispatch update style in local state when CSS panel is updated on their side
socket.on('update css data from server', (cssData: object) => {
- // console.log('CSS data received from server', cssData);
store.dispatch(updateStylesheet(cssData));
});
@@ -252,10 +244,6 @@ const RoomsContainer = (): JSX.Element => {
socket.on(
'item position data from server',
(itemPositionData: object) => {
- // console.log(
- // 'item position data received from server',
- // itemPositionData
- // );
store.dispatch(changePosition(itemPositionData));
}
);
diff --git a/app/src/components/main/DeleteButton.tsx b/app/src/components/main/DeleteButton.tsx
index 2ee7fc6d..03387b16 100644
--- a/app/src/components/main/DeleteButton.tsx
+++ b/app/src/components/main/DeleteButton.tsx
@@ -35,10 +35,6 @@ function DeleteButton({
id,
contextParam
});
-
- // console.log(
- // 'emit deleteChildAction event is triggered in DeleteButton.tsx'
- // );
}
};
diff --git a/app/src/components/main/DirectChildComponent.tsx b/app/src/components/main/DirectChildComponent.tsx
index 87268936..78183591 100644
--- a/app/src/components/main/DirectChildComponent.tsx
+++ b/app/src/components/main/DirectChildComponent.tsx
@@ -58,7 +58,6 @@ function DirectChildComponent({
componentId: componentId,
childId: childId
});
- // console.log('emit focus event from DirectChildComponent');
}
};
diff --git a/app/src/components/main/DirectChildHTML.tsx b/app/src/components/main/DirectChildHTML.tsx
index ec17c0fe..bf7a910e 100644
--- a/app/src/components/main/DirectChildHTML.tsx
+++ b/app/src/components/main/DirectChildHTML.tsx
@@ -62,7 +62,6 @@ function DirectChildHTML({
componentId: componentId,
childId: childId
});
- // console.log('emit focus event from DirectChildHTML');
}
};
diff --git a/app/src/components/main/DirectChildHTMLNestable.tsx b/app/src/components/main/DirectChildHTMLNestable.tsx
index 5591678b..f63f3fd5 100644
--- a/app/src/components/main/DirectChildHTMLNestable.tsx
+++ b/app/src/components/main/DirectChildHTMLNestable.tsx
@@ -131,10 +131,6 @@ function DirectChildHTMLNestable({
childId: childId,
contextParam: contextParam
});
-
- // console.log(
- // 'emit addChildAction event is triggered in DirectChildHTMLNestable'
- // );
}
}
}
@@ -155,10 +151,6 @@ function DirectChildHTMLNestable({
newParentChildId: childId,
contextParam: contextParam
});
-
- // console.log(
- // 'emit changePosition event is triggered in DirectChildHTMLNestable'
- // );
}
}
}
@@ -178,7 +170,6 @@ function DirectChildHTMLNestable({
componentId: componentId,
childId: childId
});
- // console.log('emit focus event from DirectChildHTMLNestable');
}
};
diff --git a/app/src/components/main/DirectChildMUI.tsx b/app/src/components/main/DirectChildMUI.tsx
index 3c728eaf..0b61dedf 100644
--- a/app/src/components/main/DirectChildMUI.tsx
+++ b/app/src/components/main/DirectChildMUI.tsx
@@ -58,7 +58,6 @@ function DirectChildMUI({ childId, name, type, typeId, style }: ChildElement): J
componentId: componentId,
childId: childId
});
- // console.log('emit focus event from DirectChildMUI');
}
};
diff --git a/app/src/components/main/DirectChildMUINestable.tsx b/app/src/components/main/DirectChildMUINestable.tsx
index 913046e3..fe0900de 100644
--- a/app/src/components/main/DirectChildMUINestable.tsx
+++ b/app/src/components/main/DirectChildMUINestable.tsx
@@ -130,10 +130,6 @@ function DirectChildMUINestable({
childId: childId,
contextParam: contextParam
});
-
- // console.log(
- // 'emit addChildAction event is triggered in DirectChildMUINestable'
- // );
}
}
}
@@ -154,10 +150,6 @@ function DirectChildMUINestable({
newParentChildId: childId,
contextParam: contextParam
});
-
- // console.log(
- // 'emit changePosition event is triggered in DirectChildMUINestable'
- // );
}
}
}
@@ -177,7 +169,6 @@ function DirectChildMUINestable({
componentId: componentId,
childId: childId
});
- // console.log('emit focus event from DirectChildMUINestable');
}
};
diff --git a/app/src/components/main/SeparatorChild.tsx b/app/src/components/main/SeparatorChild.tsx
index 4fb736f5..385f715c 100644
--- a/app/src/components/main/SeparatorChild.tsx
+++ b/app/src/components/main/SeparatorChild.tsx
@@ -111,10 +111,6 @@ function SeparatorChild({
childId: childId,
contextParam: contextParam
});
-
- // console.log(
- // 'emit addChildAction event is triggered in SeparatorChild'
- // );
}
}
}
@@ -135,10 +131,6 @@ function SeparatorChild({
newParentChildId: childId,
contextParam: contextParam
});
-
- // console.log(
- // 'emit changePosition event is triggered in SeparatorChild'
- // );
}
}
}
diff --git a/app/src/containers/CustomizationPanel.tsx b/app/src/containers/CustomizationPanel.tsx
index 744b4517..ff851abf 100644
--- a/app/src/containers/CustomizationPanel.tsx
+++ b/app/src/containers/CustomizationPanel.tsx
@@ -442,9 +442,6 @@ const CustomizationPanel = ({ isThemeLight }): JSX.Element => {
style: styleObj,
events: eventsObj
});
- // console.log(
- // 'emit updateChildAction event is triggered in CustomizationPanel.tsx'
- // );
}
return styleObj;
@@ -474,9 +471,6 @@ const CustomizationPanel = ({ isThemeLight }): JSX.Element => {
id: {},
contextParam: contextParam
});
- // console.log(
- // 'emit deleteChildAction event is triggered in CustomizationPanel.tsx'
- // );
}
};
diff --git a/app/src/helperFunctions/auth.ts b/app/src/helperFunctions/auth.ts
index a2aa0c9b..6300bd2c 100644
--- a/app/src/helperFunctions/auth.ts
+++ b/app/src/helperFunctions/auth.ts
@@ -136,7 +136,6 @@ export const updatePassword = async (
}
}
);
- console.log('Profile updated successfully:', response.data);
return response.data.message; // Returning response data directly
} catch (err) {
console.error('Error updating password:', err);
diff --git a/app/src/helperFunctions/generateCode.ts b/app/src/helperFunctions/generateCode.ts
index 61485884..7e039bdc 100644
--- a/app/src/helperFunctions/generateCode.ts
+++ b/app/src/helperFunctions/generateCode.ts
@@ -114,143 +114,51 @@ const generateUnformattedCode = (
* @returns {Array} - An array of objects representing enriched children, including components, HTML elements,
* Material UI components, and route links.
*/
- getEnrichedChildren = (
- currentComponent: Component | ChildElement | MUIComponent
- ): Array => {
+ getEnrichedChildren = (currentComponent) => {
const enrichedChildren = [];
- currentComponent.children?.forEach((child) => {
- const newChild = { ...child }; // Copy to avoid mutating original data
-
+ currentComponent.children.forEach((child) => {
+ const newChild = { ...child };
switch (child.type) {
case 'Component':
const component = components.find((c) => c.id === child.typeId);
- if (component && !imports.includes(component.name)) {
- imports.push(component.name); // Track imports to avoid duplicates
- }
- newChild.name = component?.name; // Assign the name for rendering
- break;
-
- case 'HTML Element':
- const htmlElement = HTMLTypes.find((h) => h.id === child.typeId);
- newChild.tag = htmlElement?.tag;
- if (htmlElement) {
- // If this HTML element can contain children, process them recursively
- if (
- [
- 'h1',
- 'h2',
- 'a',
- 'p',
- 'button',
- 'span',
- 'div',
- 'form',
- 'ul',
- 'ol',
- 'menu',
- 'li',
- 'Link',
- 'Switch',
- 'Route'
- ].includes(htmlElement.tag)
- ) {
- newChild.children = getEnrichedChildren(child.children);
- }
-
- // Additional flags for special types
- if (
- ['Switch', 'Route'].includes(htmlElement.tag) &&
- projectType === 'Classic React'
- ) {
- importReactRouter = true;
- } else if (htmlElement.tag === 'Link') {
- links = true;
- } else if (htmlElement.tag === 'Image') {
- images = true;
- }
+ if (component) {
+ newChild.name = component.name;
+ newChild.children = getEnrichedChildren(component); // Ensure recursion
}
break;
case 'MUI Component':
const muiComponent = MUITypes.find((m) => m.id === child.typeId);
- newChild.tag = muiComponent?.tag;
if (muiComponent) {
- // Recursively process MUI components that can have children
- if (
- [
- 'autocomplete',
- 'mui button',
- 'btn group',
- 'checkbox',
- 'fab',
- 'radio group',
- 'rating',
- 'select',
- 'slider',
- 'switch',
- 'textfield',
- 'transfer-list',
- 'toggle-button',
- 'avatar',
- 'badge',
- 'chip',
- 'divider',
- 'list',
- 'table',
- 'tooltip',
- 'typography',
- 'alert',
- 'backdrop',
- 'dialog',
- 'progress',
- 'skeleton',
- 'snackbar',
- 'accordion',
- 'appbar',
- 'card',
- 'paper',
- 'bottomNavigation',
- 'breadcrumbs',
- 'drawer',
- 'link',
- 'menu',
- 'pagination',
- 'speedDial',
- 'stepper',
- 'tabs',
- 'box',
- 'container',
- 'grid',
- 'stack',
- 'imageList',
- 'modal',
- 'popover',
- 'popper',
- 'transition'
- ].includes(muiComponent.tag)
- ) {
- newChild.children = getEnrichedChildren(child.children);
- collectMUIImports(child, MUITypes, muiImports);
- collectStateAndEventHandlers(
- child,
- MUITypes,
- muiStateAndEventHandlers
- );
+ newChild.tag = muiComponent.tag;
+ // Always process children if they exist, even if the current MUI component is not typically container-like
+ if (child.children && child.children.length > 0) {
+ newChild.children = getEnrichedChildren(child);
}
+ collectMUIImports(child, MUITypes, muiImports);
+ collectStateAndEventHandlers(
+ child,
+ MUITypes,
+ muiStateAndEventHandlers
+ );
}
break;
- case 'Route Link':
- links = true;
- newChild.name = components.find((c) => c.id === child.typeId)?.name;
+ case 'HTML Element':
+ const htmlElement = HTMLTypes.find((h) => h.id === child.typeId);
+ newChild.tag = htmlElement.tag;
+ if (child.children && child.children.length > 0) {
+ newChild.children = getEnrichedChildren(child);
+ }
break;
default:
- // Handle other types or add error handling
+ console.warn('Unhandled component type: ', child.type);
break;
}
- enrichedChildren.push(newChild); // Add the processed child to the list
+
+ enrichedChildren.push(newChild);
});
return enrichedChildren;
@@ -510,11 +418,9 @@ const generateUnformattedCode = (
attribute: string
): string => {
const before = line.substring(0, index);
- console.log('before', before);
// Remove only leading spaces from `after`, not the '>'
const after = line.substring(index).replace(/^\s+/, '');
- console.log('after', after);
// Ensure there is exactly one space before and after the inserted attribute, without removing '>'
return `${before} ${attribute.trim()} ${after}`;
@@ -641,7 +547,7 @@ const generateUnformattedCode = (
modifiedJSx = insertNestedJsxBeforeClosingTag(
modifiedJSx.join('\n'),
nestedJsx,
- level + 1
+ level
).split('\n');
}
@@ -837,7 +743,7 @@ const generateUnformattedCode = (
if (projectType === 'Classic React') {
//string to store all imports string for context
let contextImports = '';
- const { allContext } = contextParam;
+ let allContext = contextParam.allContext || []; // Set a default value if allContext is not present or falsy
for (const context of allContext) {
contextImports += `import ${context.name}Provider from '../contexts/${context.name}.js'\n`;
diff --git a/app/src/utils/createGatsbyApp.util.ts b/app/src/utils/createGatsbyApp.util.ts
index 61bba2f5..21616b35 100644
--- a/app/src/utils/createGatsbyApp.util.ts
+++ b/app/src/utils/createGatsbyApp.util.ts
@@ -146,7 +146,7 @@ export const createDefaultCSS = (
font-family: Helvetica, Arial;
}
`;
- console.log(components);
+
components.forEach((comp) => {
data += compToCSS(comp);
});
diff --git a/contributors.md b/contributors.md
index 6a2e8fe6..ae1b95c7 100644
--- a/contributors.md
+++ b/contributors.md
@@ -1,92 +1,98 @@
-| Name | LinkedIn | GitHub |
-|---------------------|-------------------------------------------------------------|----------------------------------------------------|
-| Aaron Bumanglag | [LinkedIn](https://linkedin.com/in/akbuma) | [GitHub](https://github.com/akbuma) |
-| Adam Singer | [LinkedIn](https://linkedin.com/in/adsing) | [GitHub](https://github.com/spincycle01) |
-| Adam Vanek | [LinkedIn](https://www.linkedin.com/in/atvanek) | [GitHub](https://github.com/atvanek) |
-| Abeer Faizan | [LinkedIn](https://www.linkedin.com/in/abeerfaizan) | [GitHub](https://github.com/abeer-f) |
-| Ahnaf Khan | [LinkedIn](https://www.linkedin.com/in/ahnaf-khan-844a70193) | [GitHub](https://github.com/AhnafKhvn) |
-| Alex Wolinsky | [LinkedIn](https://www.linkedin.com/in/alex-wolinsky-80ab591b2/) | [GitHub](https://github.com/aw2934/) |
-| Alex Yu | [LinkedIn](https://www.linkedin.com/in/alexjihunyu/) | [GitHub](https://github.com/buddhajjigae) |
-| Andrew Cho | [LinkedIn](https://www.linkedin.com/in/andrewjcho84/) | [GitHub](https://github.com/andrewjcho84) |
-| Anthony Torrero | [LinkedIn](https://www.linkedin.com/in/anthony-torrero-4b8798159/) | [GitHub](https://github.com/Anthonytorrero) |
-| Ben Cauffman | [LinkedIn](https://www.linkedin.com/in/benjamin-cauffman/) | [GitHub](https://github.com/BenCauffman) |
-| Bianca Picasso | [LinkedIn](https://www.linkedin.com/in/bianca-picasso) | [GitHub](https://github.com/BiancaPicasso) |
-| Brett Webster | [LinkedIn](https://www.linkedin.com/in/brett-webster-cfa-383b961) | [GitHub](https://github.com/brett-webster) |
-| Brian Han | [LinkedIn](https://www.linkedin.com/in/brianjisoohan/) | [GitHub](https://github.com/brianjshan) |
-| Brian Yan | [LinkedIn](https://www.linkedin.com/in/brianyan7/) | [GitHub](https://github.com/BrianYanGitHub) |
-| Bryan Chau | [LinkedIn](https://www.linkedin.com/in/chaubryan1/) | [GitHub](https://github.com/bchauu) |
-| Calvin Cao | [LinkedIn](http://www.linkedin.com/in/calvincao9/) | [GitHub](https://github.com/calvincao) |
-| Carly Jackson | [LinkedIn](https://www.linkedin.com/in/carly-jackson-ab9010231/) | [GitHub](https://github.com/carlyjackson) |
-| Charles Finocchiaro | [LinkedIn](https://www.linkedin.com/in/charles-finocchiaro-62440040/) | [GitHub](https://github.com/null267) |
-| Chelsey Fewer | [LinkedIn](https://www.linkedin.com/in/chelsey-fewer/) | [GitHub](https://github.com/chelseyeslehc) |
-| Chris Tang | [LinkedIn](https://www.linkedin.com/in/chrisjtang/) | [GitHub](https://github.com/chrisjtang) |
-| Christian Padilla | [LinkedIn](https://linkedin.com/in/ChristianEdwardPadilla) | [GitHub](https://github.com/ChristianEdwardPadilla) |
-| Crystal Lim | [LinkedIn](https://linkedin.com/in/crystallim) | [GitHub](https://github.com/crlim) |
-| Cyrus Burns | [LinkedIn](https://www.linkedin.com/in/cyburns/) | [GitHub](https://github.com/cyburns) |
-| Danial Reilley | [LinkedIn](https://linkedin.com/in/daniel-reilley) | [GitHub](https://github.com/dreille) |
-| Darin Ngau | [LinkedIn](https://www.linkedin.com/in/darin-ngau/) | [GitHub](https://github.com/dnngau) |
-| Daryl Foster | [LinkedIn](https://www.linkedin.com/in/darylfosterma/) | [GitHub](https://github.com/MadinventorZero) |
-| Denton Wong | [LinkedIn](https://www.linkedin.com/in/denton-wong/) | [GitHub](https://github.com/dentonwong) |
-| Diego Vazquez | [LinkedIn](https://www.linkedin.com/in/diegovazquezny/) | [GitHub](https://github.com/diegovazquezny) |
-| Edward Park | [LinkedIn](https://www.linkedin.com/in/edwardparkwork/) | [GitHub](https://github.com/eddypjr) |
-| Elena Conn | [LinkedIn](https://www.linkedin.com/in/elena-conn-366346123/) | [GitHub](https://github.com/elenaconn) |
-| Eliot Nguyen | [LinkedIn](https://linkedin.com/in/ibeeliot) | [GitHub](https://github.com/ibeeliot) |
-| Evan Crews | [LinkedIn](https://www.linkedin.com/in/evan-crews/) | [GitHub](https://github.com/Evan-Crews) |
-| Fredo Chen | [LinkedIn](https://www.linkedin.com/in/fredochen/) | [GitHub](https://github.com/fredosauce) |
-| Garrett Huston | [LinkedIn](https://www.linkedin.com/in/garrett-hutson/) | [GitHub](https://github.com/GarrettHutson) |
-| Hadrian Chan | [LinkedIn](https://www.linkedin.com/in/hadrian-chan-445a8622a) | [GitHub](https://github.com/HadriChan) |
-| Hernan Damazo | [LinkedIn](https://www.linkedin.com/in/raul-hernan-damazo-chang-9440ab191/) | [GitHub](https://github.com/raulclassico7) |
-| Huy Pham | [LinkedIn](https://www.linkedin.com/in/huypham048) | [GitHub](https://github.com/huypham048) |
-| Ian Davis | [LinkedIn](https://www.linkedin.com/in/icdavis/) | [GitHub](https://github.com/iancdavis) |
-| Jesse Zuniga | [LinkedIn](https://linkedin.com/in/jesse-zuniga) | [GitHub](https://github.com/jzuniga206) |
-| Jin Soo Lim | [LinkedIn](https://www.linkedin.com/in/jin-soo-lim-3a567b1b3/) | [GitHub](https://github.com/jinsoolim) |
-| Jon Wage | [LinkedIn](http://linkedin.com/in/johnwage) | [GitHub](http://github.com/johnwage) |
-| Jonathan Calvo Ramirez | [LinkedIn](https://www.linkedin.com/in/jonathan-calvo/) | [GitHub](https://github.com/jonocr) |
-| Julie Wu | [LinkedIn](https://www.linkedin.com/in/jwuarchitect/) | [GitHub](https://github.com/yutingwu4) |
-| Katrina Henderson | [LinkedIn](https://www.linkedin.com/in/katrinahenderson/) | [GitHub](https://github.com/kchender) |
-| Ken Bains | [LinkedIn](https://www.linkedin.com/in/ken-bains) | [GitHub](https://github.com/ken-Bains) |
-| Kevin Park | [LinkedIn](https://www.linkedin.com/in/xkevinpark/) | [GitHub](https://github.com/xkevinpark) |
-| Khuong Nguyen | [LinkedIn](https://www.linkedin.com/in/khuong-nguyen/) | [GitHub](https://github.com/khuongdn16) |
-| Laura Forden | [LinkedIn](https://www.linkedin.com/in/la-forden/) | [GitHub](https://github.com/lauraafor) |
-| Lauren Leer | [LinkedIn](https://www.linkedin.com/in/lauren-leer/) | [GitHub](https://github.com/LALeer) |
-| Liam Roh | [LinkedIn](https://www.linkedin.com/in/liam-roh/) | [GitHub](https://github.com/liamroh) |
-| Lillian Wimberly | [LinkedIn](https://www.linkedin.com/in/lillianwimberly/) | [GitHub](https://github.com/lillwimberly) |
-| Linh Tran | [LinkedIn](https://www.linkedin.com/in/linhtran51/) | [GitHub](https://github.com/Linhatran) |
-| Luke Madden | [LinkedIn](https://www.linkedin.com/in/lukemadden/) | [GitHub](https://github.com/lukemadden) |
-| Matteo Diterlizzi | [LinkedIn](https://www.linkedin.com/in/matteo-diterlizzi-564166107/) | [GitHub](https://github.com/MatteoDiter) |
-| Michael Ng | [LinkedIn](https://www.linkedin.com/in/michaelng2/) | [GitHub](https://github.com/MikoGome) |
-| Mike Dunnmon | [LinkedIn](https://www.linkedin.com/in/michaeldunnmon/) | [GitHub](https://github.com/mdunnmon) |
-| Miles Wright | [LinkedIn](https://www.linkedin.com/in/miles-m-wright) | [GitHub](https://github.com/Miles818) |
-| Mitchel Severe | [LinkedIn](https://www.linkedin.com/in/misevere/) | [GitHub](https://github.com/mitchelsevere) |
-| Nam Ha | [LinkedIn](https://www.linkedin.com/in/namos2502) | [GitHub](https://github.com/namos2502) |
-| Natalie Vick | [LinkedIn](https://www.linkedin.com/in/vicknatalie/) | [GitHub](https://github.com/natattackvick) |
-| Nel Malikova | [LinkedIn](https://www.linkedin.com/in/gmalikova/) | [GitHub](https://github.com/gmal1) |
-| Philip Hua | [LinkedIn](https://www.linkedin.com/in/philip-minh-hua) | [GitHub](https://github.com/pmhua) |
-| Rachel Kucharski | [LinkedIn](https://www.linkedin.com/in/rachelkucharski/) | [GitHub](https://github.com/rachelk585) |
-| Rick McGrath | [LinkedIn](https://www.linkedin.com/in/rick-mcgrath-b1617126b) | [GitHub](https://github.com/r-mcgrath) |
-| Ron Fu | [LinkedIn](https://www.linkedin.com/in/ronfu) | [GitHub](https://github.com/rfvisuals) |
-| Rose Jiang | [LinkedIn](https://www.linkedin.com/in/rose-jiang/) | [GitHub](https://github.com/jujupro) |
-| Salvatore Saluga | [LinkedIn](https://www.linkedin.com/in/salvatore-saluga) | [GitHub](https://github.com/SalSaluga) |
-| Sang-Hoon (Sean) Kil | [LinkedIn](https://www.linkedin.com/in/sanghkil/) | [GitHub](https://github.com/Skilzsz) |
-| Sean Sadykoff | [LinkedIn](https://www.linkedin.com/in/sean-sadykoff/) | [GitHub](https://github.com/sean1292) |
-| Shana Hoehn | [LinkedIn](https://www.linkedin.com/in/shana-hoehn-70297b169/) | [GitHub](https://github.com/slhoehn) |
-| Shirley Liu | [LinkedIn](https://www.linkedin.com/in/yijunliu/) | [GitHub](https://github.com/yijunliu90) |
-| Shlomo Porges | [LinkedIn](https://linkedin.com/shlomoporges) | [GitHub](https://github.com/ShlomoPorges) |
-| Sonya Hu | [LinkedIn](https://www.linkedin.com/in/sonyahu25) | [GitHub](https://github.com/sonyahu15) |
-| Sophia Bui | [LinkedIn](https://linkedin.com/in/sophiabui) | [GitHub](https://github.com/sophia-bui) |
-| Sophia Huttner | [LinkedIn](https://www.linkedin.com/in/sophia-huttner-68315975/) | [GitHub](https://github.com/sophjean) |
-| Stephen Kim | [LinkedIn](https://www.linkedin.com/in/stephenkim612/) | [GitHub](https://github.com/stephenkim612) |
-| Stormi Hashimoto | [LinkedIn](https://www.linkedin.com/in/stormikph/) | [GitHub](https://github.com/stormikph) |
-| Thomas Lukasiewicz | [LinkedIn](https://www.linkedin.com/in/thomas-lukasiewicz-27676273/) | [GitHub](https://github.com/tlukasiewicz89) |
-| Tolga Mizrakci | [LinkedIn](https://linkedin.com/in/tolga-mizrakci) | [GitHub](https://github.com/tolgamizrakci) |
-| Tony Ito-Cole | [LinkedIn](https://linkedin.com/in/tony-ito-cole) | [GitHub](https://github.com/tonyito) |
-| Tyler Sullberg | [LinkedIn](https://www.linkedin.com/in/tyler-sullberg) | [GitHub](https://github.com/tsully) |
-| Ulrich Neujahr | [LinkedIn](https://www.linkedin.com/in/nobrackets/) | [GitHub](https://github.com/nobrackets) |
-| Victor Martins | [LinkedIn](https://www.linkedin.com/in/victor-martins-542611186/) | [GitHub](https://github.com/martins5225) |
-| William Cheng | [LinkedIn](https://www.linkedin.com/in/william-cheng-0723/) | [GitHub](https://github.com/WilliamCheng12345) |
-| William Rittwage | [LinkedIn](https://www.linkedin.com/in/william-rittwage) | [GitHub](https://github.com/wbrittwage) |
-| William Yoon | [LinkedIn](https://www.linkedin.com/in/williamdyoon/) | [GitHub](https://github.com/williamdyoon) |
-| Xiao Wang | [LinkedIn](https://www.linkedin.com/in/xiao-wang-03183285/) | [GitHub](https://github.com/wang9hu) |
-| Yameng Zhang | [LinkedIn](https://www.linkedin.com/in/yameng-zhang612/) | [GitHub](https://github.com/Eliza612) |
-| Yohan Jeon | [LinkedIn](https://www.linkedin.com/in/yohan-jeon1) | [GitHub](https://github.com/Yoheze) |
-| Yuanji Huang | [LinkedIn](https://www.linkedin.com/in/yuanjihuang/) | [GitHub](https://github.com/kr1spybacon) |
+| Name | LinkedIn | GitHub |
+| ---------------------- | --------------------------------------------------------------------------- | --------------------------------------------------- |
+| Austin Alvarez | [LinkedIn](https://www.linkedin.com/in/austin-orion-alvarez/) | [GitHub](https://github.com/InvectivusTaco) |
+| Aaron Bumanglag | [LinkedIn](https://linkedin.com/in/akbuma) | [GitHub](https://github.com/akbuma) |
+| Adam Singer | [LinkedIn](https://linkedin.com/in/adsing) | [GitHub](https://github.com/spincycle01) |
+| Adam Vanek | [LinkedIn](https://www.linkedin.com/in/atvanek) | [GitHub](https://github.com/atvanek) |
+| Abeer Faizan | [LinkedIn](https://www.linkedin.com/in/abeerfaizan) | [GitHub](https://github.com/abeer-f) |
+| Ahnaf Khan | [LinkedIn](https://www.linkedin.com/in/ahnaf-khan-844a70193) | [GitHub](https://github.com/AhnafKhvn) |
+| Alex Wolinsky | [LinkedIn](https://www.linkedin.com/in/alex-wolinsky-80ab591b2/) | [GitHub](https://github.com/aw2934/) |
+| Alex Yu | [LinkedIn](https://www.linkedin.com/in/alexjihunyu/) | [GitHub](https://github.com/buddhajjigae) |
+| Andrew Cho | [LinkedIn](https://www.linkedin.com/in/andrewjcho84/) | [GitHub](https://github.com/andrewjcho84) |
+| Anthony Torrero | [LinkedIn](https://www.linkedin.com/in/anthony-torrero-4b8798159/) | [GitHub](https://github.com/Anthonytorrero) |
+| Ben Cauffman | [LinkedIn](https://www.linkedin.com/in/benjamin-cauffman/) | [GitHub](https://github.com/BenCauffman) |
+| Bianca Picasso | [LinkedIn](https://www.linkedin.com/in/bianca-picasso) | [GitHub](https://github.com/BiancaPicasso) |
+| Brett Webster | [LinkedIn](https://www.linkedin.com/in/brett-webster-cfa-383b961) | [GitHub](https://github.com/brett-webster) |
+| Brian Han | [LinkedIn](https://www.linkedin.com/in/brianjisoohan/) | [GitHub](https://github.com/brianjshan) |
+| Brian Yan | [LinkedIn](https://www.linkedin.com/in/brianyan7/) | [GitHub](https://github.com/BrianYanGitHub) |
+| Bryan Chau | [LinkedIn](https://www.linkedin.com/in/chaubryan1/) | [GitHub](https://github.com/bchauu) |
+| Calvin Cao | [LinkedIn](http://www.linkedin.com/in/calvincao9/) | [GitHub](https://github.com/calvincao) |
+| Carly Jackson | [LinkedIn](https://www.linkedin.com/in/carly-jackson-ab9010231/) | [GitHub](https://github.com/carlyjackson) |
+| Charles Finocchiaro | [LinkedIn](https://www.linkedin.com/in/charles-finocchiaro-62440040/) | [GitHub](https://github.com/null267) |
+| Chelsey Fewer | [LinkedIn](https://www.linkedin.com/in/chelsey-fewer/) | [GitHub](https://github.com/chelseyeslehc) |
+| Chris Tang | [LinkedIn](https://www.linkedin.com/in/chrisjtang/) | [GitHub](https://github.com/chrisjtang) |
+| Christian Padilla | [LinkedIn](https://linkedin.com/in/ChristianEdwardPadilla) | [GitHub](https://github.com/ChristianEdwardPadilla) |
+| Crystal Lim | [LinkedIn](https://linkedin.com/in/crystallim) | [GitHub](https://github.com/crlim) |
+| Cyrus Burns | [LinkedIn](https://www.linkedin.com/in/cyburns/) | [GitHub](https://github.com/cyburns) |
+| Danial Reilley | [LinkedIn](https://linkedin.com/in/daniel-reilley) | [GitHub](https://github.com/dreille) |
+| Darin Ngau | [LinkedIn](https://www.linkedin.com/in/darin-ngau/) | [GitHub](https://github.com/dnngau) |
+| Daryl Foster | [LinkedIn](https://www.linkedin.com/in/darylfosterma/) | [GitHub](https://github.com/MadinventorZero) |
+| Denton Wong | [LinkedIn](https://www.linkedin.com/in/denton-wong/) | [GitHub](https://github.com/dentonwong) |
+| Diego Vazquez | [LinkedIn](https://www.linkedin.com/in/diegovazquezny/) | [GitHub](https://github.com/diegovazquezny) |
+| Edward Park | [LinkedIn](https://www.linkedin.com/in/edwardparkwork/) | [GitHub](https://github.com/eddypjr) |
+| Elena Conn | [LinkedIn](https://www.linkedin.com/in/elena-conn-366346123/) | [GitHub](https://github.com/elenaconn) |
+| Eliot Nguyen | [LinkedIn](https://linkedin.com/in/ibeeliot) | [GitHub](https://github.com/ibeeliot) |
+| Evan Crews | [LinkedIn](https://www.linkedin.com/in/evan-crews/) | [GitHub](https://github.com/Evan-Crews) |
+| Fredo Chen | [LinkedIn](https://www.linkedin.com/in/fredochen/) | [GitHub](https://github.com/fredosauce) |
+| Garrett Huston | [LinkedIn](https://www.linkedin.com/in/garrett-hutson/) | [GitHub](https://github.com/GarrettHutson) |
+| Hadrian Chan | [LinkedIn](https://www.linkedin.com/in/hadrian-chan-445a8622a) | [GitHub](https://github.com/HadriChan) |
+| Heather Pfeiffer | [LinkedIn](https://www.linkedin.com/in/heathermpfeiffer/) | [GitHub](https://github.com/HM-Pfeiffer) |
+| Hernan Damazo | [LinkedIn](https://www.linkedin.com/in/raul-hernan-damazo-chang-9440ab191/) | [GitHub](https://github.com/raulclassico7) |
+| Huy Pham | [LinkedIn](https://www.linkedin.com/in/huypham048) | [GitHub](https://github.com/huypham048) |
+| Ian Davis | [LinkedIn](https://www.linkedin.com/in/icdavis/) | [GitHub](https://github.com/iancdavis) |
+| Jesse Wowczuck | [LinkedIn](https://www.linkedin.com/in/jessewowczuk) | [GitHub](https://github.com/JesseWowczuk) |
+| Jesse Zuniga | [LinkedIn](https://linkedin.com/in/jesse-zuniga) | [GitHub](https://github.com/jzuniga206) |
+| Jin Soo Lim | [LinkedIn](https://www.linkedin.com/in/jin-soo-lim-3a567b1b3/) | [GitHub](https://github.com/jinsoolim) |
+| Jon Wage | [LinkedIn](http://linkedin.com/in/johnwage) | [GitHub](http://github.com/johnwage) |
+| Jonathan Calvo Ramirez | [LinkedIn](https://www.linkedin.com/in/jonathan-calvo/) | [GitHub](https://github.com/jonocr) |
+| Julie Wu | [LinkedIn](https://www.linkedin.com/in/jwuarchitect/) | [GitHub](https://github.com/yutingwu4) |
+| Katrina Henderson | [LinkedIn](https://www.linkedin.com/in/katrinahenderson/) | [GitHub](https://github.com/kchender) |
+| Ken Bains | [LinkedIn](https://www.linkedin.com/in/ken-bains) | [GitHub](https://github.com/ken-Bains) |
+| Kevin Park | [LinkedIn](https://www.linkedin.com/in/xkevinpark/) | [GitHub](https://github.com/xkevinpark) |
+| Khuong Nguyen | [LinkedIn](https://www.linkedin.com/in/khuong-nguyen/) | [GitHub](https://github.com/khuongdn16) |
+| Laura Forden | [LinkedIn](https://www.linkedin.com/in/la-forden/) | [GitHub](https://github.com/lauraafor) |
+| Lauren Leer | [LinkedIn](https://www.linkedin.com/in/lauren-leer/) | [GitHub](https://github.com/LALeer) |
+| Liam Roh | [LinkedIn](https://www.linkedin.com/in/liam-roh/) | [GitHub](https://github.com/liamroh) |
+| Lillian Wimberly | [LinkedIn](https://www.linkedin.com/in/lillianwimberly/) | [GitHub](https://github.com/lillwimberly) |
+| Linh Tran | [LinkedIn](https://www.linkedin.com/in/linhtran51/) | [GitHub](https://github.com/Linhatran) |
+| Luke Madden | [LinkedIn](https://www.linkedin.com/in/lukemadden/) | [GitHub](https://github.com/lukemadden) |
+| Matteo Diterlizzi | [LinkedIn](https://www.linkedin.com/in/matteo-diterlizzi-564166107/) | [GitHub](https://github.com/MatteoDiter) |
+| Michael Ng | [LinkedIn](https://www.linkedin.com/in/michaelng2/) | [GitHub](https://github.com/MikoGome) |
+| Mike Dunnmon | [LinkedIn](https://www.linkedin.com/in/michaeldunnmon/) | [GitHub](https://github.com/mdunnmon) |
+| Miles Wright | [LinkedIn](https://www.linkedin.com/in/miles-m-wright) | [GitHub](https://github.com/Miles818) |
+| Mitchel Severe | [LinkedIn](https://www.linkedin.com/in/misevere/) | [GitHub](https://github.com/mitchelsevere) |
+| Nam Ha | [LinkedIn](https://www.linkedin.com/in/namos2502) | [GitHub](https://github.com/namos2502) |
+| Natalie Vick | [LinkedIn](https://www.linkedin.com/in/vicknatalie/) | [GitHub](https://github.com/natattackvick) |
+| Nel Malikova | [LinkedIn](https://www.linkedin.com/in/gmalikova/) | [GitHub](https://github.com/gmal1) |
+| Philip Hua | [LinkedIn](https://www.linkedin.com/in/philip-minh-hua) | [GitHub](https://github.com/pmhua) |
+| Rachel Kucharski | [LinkedIn](https://www.linkedin.com/in/rachelkucharski/) | [GitHub](https://github.com/rachelk585) |
+| Rick McGrath | [LinkedIn](https://www.linkedin.com/in/rick-mcgrath-b1617126b) | [GitHub](https://github.com/r-mcgrath) |
+| Ron Fu | [LinkedIn](https://www.linkedin.com/in/ronfu) | [GitHub](https://github.com/rfvisuals) |
+| Rose Jiang | [LinkedIn](https://www.linkedin.com/in/rose-jiang/) | [GitHub](https://github.com/jujupro) |
+| Salvatore Saluga | [LinkedIn](https://www.linkedin.com/in/salvatore-saluga) | [GitHub](https://github.com/SalSaluga) |
+| Sang-Hoon (Sean) Kil | [LinkedIn](https://www.linkedin.com/in/sanghkil/) | [GitHub](https://github.com/Skilzsz) |
+| Sean Ryan | [LinkedIn](https://www.linkedin.com/in/sean-francis-ryan/) | [GitHub](https://github.com/sfryan95) |
+| Sean Sadykoff | [LinkedIn](https://www.linkedin.com/in/sean-sadykoff/) | [GitHub](https://github.com/sean1292) |
+| Shana Hoehn | [LinkedIn](https://www.linkedin.com/in/shana-hoehn-70297b169/) | [GitHub](https://github.com/slhoehn) |
+| Shirley Liu | [LinkedIn](https://www.linkedin.com/in/yijunliu/) | [GitHub](https://github.com/yijunliu90) |
+| Shlomo Porges | [LinkedIn](https://linkedin.com/shlomoporges) | [GitHub](https://github.com/ShlomoPorges) |
+| Sonya Hu | [LinkedIn](https://www.linkedin.com/in/sonyahu25) | [GitHub](https://github.com/sonyahu15) |
+| Sophia Bui | [LinkedIn](https://linkedin.com/in/sophiabui) | [GitHub](https://github.com/sophia-bui) |
+| Sophia Huttner | [LinkedIn](https://www.linkedin.com/in/sophia-huttner-68315975/) | [GitHub](https://github.com/sophjean) |
+| Stephen Kim | [LinkedIn](https://www.linkedin.com/in/stephenkim612/) | [GitHub](https://github.com/stephenkim612) |
+| Stormi Hashimoto | [LinkedIn](https://www.linkedin.com/in/stormikph/) | [GitHub](https://github.com/stormikph) |
+| Thomas Lukasiewicz | [LinkedIn](https://www.linkedin.com/in/thomas-lukasiewicz-27676273/) | [GitHub](https://github.com/tlukasiewicz89) |
+| Tolga Mizrakci | [LinkedIn](https://linkedin.com/in/tolga-mizrakci) | [GitHub](https://github.com/tolgamizrakci) |
+| Tony Ito-Cole | [LinkedIn](https://linkedin.com/in/tony-ito-cole) | [GitHub](https://github.com/tonyito) |
+| Tyler Sullberg | [LinkedIn](https://www.linkedin.com/in/tyler-sullberg) | [GitHub](https://github.com/tsully) |
+| Ulrich Neujahr | [LinkedIn](https://www.linkedin.com/in/nobrackets/) | [GitHub](https://github.com/nobrackets) |
+| Victor Martins | [LinkedIn](https://www.linkedin.com/in/victor-martins-542611186/) | [GitHub](https://github.com/martins5225) |
+| William Cheng | [LinkedIn](https://www.linkedin.com/in/william-cheng-0723/) | [GitHub](https://github.com/WilliamCheng12345) |
+| William Rittwage | [LinkedIn](https://www.linkedin.com/in/william-rittwage) | [GitHub](https://github.com/wbrittwage) |
+| William Yoon | [LinkedIn](https://www.linkedin.com/in/williamdyoon/) | [GitHub](https://github.com/williamdyoon) |
+| Xiao Wang | [LinkedIn](https://www.linkedin.com/in/xiao-wang-03183285/) | [GitHub](https://github.com/wang9hu) |
+| Yameng Zhang | [LinkedIn](https://www.linkedin.com/in/yameng-zhang612/) | [GitHub](https://github.com/Eliza612) |
+| Yohan Jeon | [LinkedIn](https://www.linkedin.com/in/yohan-jeon1) | [GitHub](https://github.com/Yoheze) |
+| Yuanji Huang | [LinkedIn](https://www.linkedin.com/in/yuanjihuang/) | [GitHub](https://github.com/kr1spybacon) |
+| Zack Vandiver | [LinkedIn](https://www.linkedin.com/in/zackvandiver/) | [GitHub](https://github.com/zackvandiver) |
+
diff --git a/mockData.ts b/mockData.ts
index 76fe5307..1c132a7a 100644
--- a/mockData.ts
+++ b/mockData.ts
@@ -1,4 +1,4 @@
-import HTMLTypes from "./app/src/redux/HTMLTypes";
+import HTMLTypes from './app/src/redux/HTMLTypes';
const mockObj = {
//these user credentials were created via the signup page
@@ -7,7 +7,7 @@ const mockObj = {
username: 'test',
email: 'test@gmail.com',
password: 'password1!',
- userId: '663e974c97c5dfbf7d204e78'
+ userId: '664247b09df40d692fb7fdef'
},
state: {
@@ -30,8 +30,8 @@ const mockObj = {
nextTopSeparatorId: 1000,
HTMLTypes: HTMLTypes, // left as is for now
tailwind: false,
- stylesheet: '',
- codePreview: false,
+ stylesheet: '',
+ codePreview: false
},
projectToSave: {
@@ -59,18 +59,18 @@ const mockObj = {
nextTopSeparatorId: 1000,
HTMLTypes: HTMLTypes, // left as is for now
tailwind: false,
- stylesheet: '',
- codePreview: false,
+ stylesheet: '',
+ codePreview: false
},
userId: {
- "$oid": "663e974c97c5dfbf7d204e78"
+ $oid: '664247b09df40d692fb7fdef'
},
username: 'test',
createdAt: Date.now(),
isLoggedIn: false,
- comments: [],
+ comments: []
},
-//The following is for graphQL
+ //The following is for graphQL
GET_PROJECTS: `query GetAllProjects($userId: ID) {
getAllProjects(userId: $userId) {
name
diff --git a/package.json b/package.json
index b2f075d5..2ab48db5 100644
--- a/package.json
+++ b/package.json
@@ -6,6 +6,11 @@
"main": "app/.electron/main.js",
"author": "OS Labs",
"contributors": [
+ "Heather Pfieffer",
+ "Sean Ryan",
+ "Austin Alvarez",
+ "Zack Vandiver",
+ "Jesse Wowczuk",
"Victor Martins",
"Liam Roh",
"Denton Wong",
@@ -46,6 +51,7 @@
"Eliot Nguyen",
"Evan Crews",
"Fredo Chen",
+ "Heather Pfeiffer",
"Jesse Zuniga",
"Jin Soo Lim",
"Jonathan Calvo Ramirez",
diff --git a/resources/v21 Demo.gif b/resources/v21 Demo.gif
new file mode 100644
index 0000000000000000000000000000000000000000..6d1607dadbd697fabb47af4e8f40b6f454edcceb
GIT binary patch
literal 1491007
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 LN8{o7PCP?JW0V
zDyy7AXJ;%MFVBH2v#h4?WITta*OcmyCM#}V(;5gGP%f*k8#%Gi$HnB*e8&(ZMr2Ea4utF1?i6}=2+bp*-R6tU|#$>TlMKrgbM+O5Xsimx2_Qx7nU!V2ulsdv*?E-
zO`Wk{AMDS|H?G`Q6%sDxNNn3;^AfQ*_BWv+Kwji>(FeBE$D$ko2`I
z+8$9o%Z%82ROWeD+<~m^U{ixw#J>8T)wY3Yil%c8o!pp0Jj@Q0XQLLWr7so@yTL5Y
z?Pj=Dq0*%E>pGIwKVdWJWKQP5jiOgaO^fWx^RKm@P(6!p3^E>fd(tqXtKe@fB4y%&@S6UIeLf}r$
ziTkf+tLiVrebVaOeIofTP~j+E_-IQ9D^a!!aH_4u{2I#E7P{xDfhlCOy&S|4pz
zu$OWAV||IkY+b6#Mjbg%bgdy5jA)mZj(9l+%9i8nf}m
zk)GxswsSm6M>b5vj*Wp-(XS=}rxl-L)Y2%VYp;Zs!khM|&U?SC>3d=aXpke!D@seh
z{zxDy=~ulx4JJ&0fgOG`%8+l^_4B~f(=7nQn5e2!`B@8AmYn8)`M-A@K
zyd~_kQpPBIc|ZmOYl6iN6L8<0Kf8XdcUqX?b3h_BBQy3qy`Tst#8e%J4(`qoX00M~
z4Ki{c{qhg^+6IO*_`9SY>4XB~?mrFx!GJ9ouQ}sb!eMPS=n_;@|3?V#j5x)~kNs-P
zy%Sy@lc0hMQHg2&YS-l8s{z)AG20{xO*KV703W9LE>&AvpekI9Y0rmX?BaSVn}-`%
zza!6{t>PtjGI#n)OnfObn(kE4k-%wEq@|*p$fzOL1CgKav@h{i||;-Yt@#NipY*7UsPv
z@7ZAgbwsr*d3a9hLYMmCqqme=W?coFOzayo
zR_9qYIX)M}NyJ~D(qC=4^hSH|$O&78>K<^nQy{eqo@d=yNwaUnG&8@AAHqFj)pRB<
zb;@xsUDNR2?vJM(n-w@>hRDTdcZImDzAfJ_z?!rm7Zxw~R#)!O%m?T5#(-6Tc+O?vu1A~3wd;lskImzKd`B>u0w1H7^OQK2
zrPAEih)w#AxAIy13|3byXUP_4DnA&B&nJOv#2HRUwO~o>!8;tc^`4C=OeS4y=@`6q
zi}1-NMhpV?hnouJ)qvVyTTPG%Mm!KW&3sSR;hf*ck0odax@|_Qf}S&3wa38oGq~wh
z(xrvdSxa>ry0NDmti)~UV2Mjs})LQ?XbKu*-4lC4