Skip to content

Commit

Permalink
Merge pull request #36 from UniRegensburg/dev
Browse files Browse the repository at this point in the history
First deployment
  • Loading branch information
Roy-j-Xu authored Oct 7, 2024
2 parents 8048f90 + ff30a9d commit 951bc53
Show file tree
Hide file tree
Showing 54 changed files with 9,155 additions and 1 deletion.
24 changes: 24 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
42 changes: 41 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,41 @@
# mme-sose24-statistics
# mme-sose24-statistics

## About the app

Try it out with this link: [https://UniRegensburg.github.io/mme-sose24-statistics/](https://UniRegensburg.github.io/mme-sose24-statistics/).

## Setup

To install the application, run

```bash
$ git clone https://github.com/UniRegensburg/mme-sose24-statistics.git
$ cd mme-sose24-statistics
$ npm install
```

To start, run

```bash
$ npm run dev
```

## Technologies

- Vite
- Vitest
- React
- D3.js
- Material UI

## Documentations

### Developer guidelines

See [GUIDELINES.md](docs/GUIDELINES.md)

### Tutorials for developers

[Tutorial on Entities](docs/tutorials/tutorial-entities.md)

[Tutorial on Services](docs/tutorials/tutorial-services.md)
43 changes: 43 additions & 0 deletions docs/GUIDELINES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Developer Guidelines

## Directory Structure

### Root folder

- **`src/`**: Contains all source files.
- **`docs/`**: Documentations, screenshots, etc.
- **`public/`**: Assets that are not referenced in the source code.

### `src/` folder

- **`app/pages/`**: Contains subfolders. Each subfolders contains all specialized components used in a single page.
- **`components/`**: Reusable React components.

- **`services/`**: Service classes responsible for complex utility logics.
- **`entities/`**: Data models and schemas.
- **`exceptions/`**: Custom exceptions and exception handlers.
- **`utils/`**: Utility functions and helpers.
- **`assets/`**: Static resources. Pictures, icons, or pre-defined JSON files, etc.

## Code Style Conventions

- **Indentation**: Use 2 spaces for indentation.

- **Naming:** Use `camelCase` for variables and functions, `PascalCase` for classes and file names.

- **Comments**: Use JSDoc for React components. For instance:

```jsx
/**
* A greeting message to the user.
*
* @param {string} name The user's name.
* @param {number} id User's ID.
* @returns {ReactNode} Rendered div component
*/
function Greeting({ name, id }) {
return <div>Hello {name}, you are our {id}-th user!</div>;
}
```


169 changes: 169 additions & 0 deletions docs/tutorials/tutorial-entities.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
# Tutorial on Entities

## `DataEntity`

The class `DataEntity` stores a table of questionnaire data and user information. A `DataEntity` contains information of its questionnaire type, data and columns. The following is an example of a `DataEntity` of rawTLX questionnaire with 2 rows of data.

```javascript
DataEntity {
type: {
name: 'rawTLX',
numOfQuestions: 6,
minValue: 0,
maxValue: 20,
scoreCalculator: [Function: scoreCalculator],
scoreInterpretor: [Function: scoreInterpretor]
},
data:
[
{ Q1: 11, Q2: 18, Q3: 18, Q4: 17, Q5: 19, Q6: 9, id: 1, age: 33, 'T:Q1+Q2': 29 },
{ Q1: 13, Q2: 2, Q3: 10, Q4: 14, Q5: 17, Q6: 18, id: 2, age: 21, 'T:Q1+Q2': 15 }
],
columns: {
userInfo: [ 'id', 'age' ],
questions: [
'Q1', 'Q2', 'Q3',
'Q4', 'Q5', 'Q6',
'Q7', 'Q8'
],
transform: [ 'T:Q1+Q2' ]
}
}
```

- `type`: The type of questionnaire.
- `data`: The raw data, represented by an array of objects. When performing data manipulation on the data, **do not** access the raw data like `dataEntity.data[row]["col"]`, **you are required to use the appropriate member functions instead**.
- `columns`: Stores information about columns.

### Constructor

The constructor of `DataEntity` takes in questionnaire type and data, both are optional. The constructor automatically detect questionnaire columns and user info columns.

```javascript
const dataEntity = new DataEntity(
QUESTIONNAIRE_TYPE.NONE,
[
{ Q1: 5, Q2: 5, id: 1, 'T:Q1+Q2': 10 },
{ Q1: 4, Q2: 3, id: 2, 'T:Q1+Q2': 7 },
]
)
console.log(dataEntity)
// Result:
//
// DataEntity {
// type: {
// name: 'NONE',
// numOfQuestions: 9007199254740991,
// minValue: -9007199254740991,
// maxValue: 9007199254740991,
// scoreCalculator: [Function: scoreCalculator],
// scoreInterpretor: [Function: scoreInterpretor]
// },
// data:
// [
// { Q1: 5, Q2: 5, id: 1, 'T:Q1+Q2': 10 },
// { Q1: 4, Q2: 3, id: 2, 'T:Q1+Q2': 7 },
// ],
// columns: {
// userInfo: [ 'id' ],
// questions: [ 'Q1', 'Q2' ],
// transform: [ 'T:Q1+Q2' ]
// }
// }

```

### Column operations

| Function | Description | Notes |
| --------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------ |
| addQuestions(numOfQuestions=1) | Add given number of new questions to the questionnaire. | Only NONE-type data allows adding new questions. |
| deleteQuestions(numOfQuestions=1) | Delete given number of new questions to the questionnaire. | Only NONE-type data allows setting number of questions |
| addUserInfoColumns(columns) | Given a string or an array of strings, add new strings among them as user info columns. | Existing columns will not be added again. |
| addTransformColumns(expressions) | Given a string or an array of strings, create transform columns with those name and fill those columns with the transformed data. | Do not include `'T:'` in the input. |
| deleteColumns(columns) | Given a string or an array of strings, delete columns with those names. | Only works for `userInfo` and `transform` columns. |

### Row operations

| Function | Description |
| ---------------------------- | ---------------------------------------------- |
| addEmptyRows(numberOfRows=1) | Append given number of empty rows to the data. |
| insertEmptyRow(index) | Insert 1 empty row at the given index. |

### Data manipulation

| Function | Description | Notes |
| ------------------------------ | ------------------------------------------------- | ------------------------------------------------- |
| setValue(rowNr, column, value) | Set value at the given and row number and column. | Data in transform columns cannot be manually set. |
| setType(type) | Set questionnaire type. | |

### Getters

| Function | Description |
| --------------------- | ------------------------------------------------- |
| get size() | Get number of rows of data. |
| get numOfQuestions() | Get number of questions. |
| get allColumns() | Get a list of all columns. |
| get userInfoColumns() | Get a list of user info columns. |
| get questionColumns() | Get a list of question columns. |
| getType() | Get a string of questionnaire type name. |
| row(rowNumber) | Get a single row of data. |
| col(columnName) | Get data from a column as an array. |
| loc(rowNr, column) | Get the value at the given row number and column. |

### Example

Using the same `dataEntity` we created earlier:

```javascript
console.log(dataEntity.getType())
// Result: NONE

dataEntity.addQuestions() // This add 1 question by default
console.log(dataEntity.questionColumns)
// Result: [ 'Q1', 'Q2', 'Q3' ]

dataEntity.addUserInfoColumns(["id", "age"]) // Existing columns are not added twice
dataEntity.addUserInfoColumns("gender")
console.log(dataEntity.allColumns)
// Result" [ 'Q1', 'Q2', 'Q3', 'id', 'age', 'gender', 'T:Q1+Q2' ]

dataEntity.addEmptyRows(2)
dataEntity.setValue(2, "Q1", 1000)
console.log(dataEntity.loc(2, "Q1")) // Get value at the 3rd row in column Q1
// Result: 1000
console.log(dataEntity)
// Result:
//
// DataEntity {
// type: {
// name: 'NONE',
// numOfQuestions: 9007199254740991,
// minValue: -9007199254740991,
// maxValue: 9007199254740991,
// scoreCalculator: [Function: scoreCalculator],
// scoreInterpretor: [Function: scoreInterpretor]
// },
// data:
// [
// { Q1: 5, Q2: 5, Q3: null, id: 1, age: null, gender: null, 'T:Q1+Q2': 10 },
// { Q1: 4, Q2: 3, Q3: null, id: null, age: null, gender: null, 'T:Q1+Q2': 7 },
// { Q1: 1000, Q2: null, Q3: null, id: null, age: null, gender: null, 'T:Q1+Q2': null },
// ],
// columns: {
// userInfo: [ 'id', 'age', 'gender' ],
// questions: [ 'Q1', 'Q2', 'Q3' ],
// transform: [ 'T:Q1+Q2' ]
// }
// }
```

## `DiagramEntity`

`DiagramEntity` is a data structure to store all information needed to plot a single diagram. It contains a diagram type, a reference to its data source (a `DataEntity`), and options for plotting.

This class is relatively easy to understand. You can refer to the source code in `src\entities\DiagramEntity.js` for more information.

## `WorkspaceEntity`

The sole purpose of `WorkspaceEntity` is to store current `dataEntity` and `diagramEntity`.
29 changes: 29 additions & 0 deletions docs/tutorials/tutorial-services.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Tutorial on Services

Services are global objects that provide static utility functions. An example:

```javascript
import dataService from "../../src/services/DataService"
import dataAnalysisService from "../../src/services/DataAnalysisService"
import QUESTIONNAIRE_TYPE from "../../src/constants/QuestionnaireType"

dataService.importData("./tests/test-data/SUS-example.csv", QUESTIONNAIRE_TYPE.SUS)
.then(dataEntity => {
const scores = dataAnalysisService.calculateScores(dataEntity)
console.log(scores)
})
```

Service objects are usually straightforward. You are encouraged to refer to the source code in `src\services` to learn about them.

## `dataService`

This service deal with import/export of `DataEntity`.

Particularly, `dataService.importData` is a asynchronous function that generates a `DataEntity` from a CSV file.

If you are not familiar with asynchronous functions, see https://www.w3schools.com/js/js_async.asp.

## `dataAnalysisService`

This service deal with data analysis. It calculated scores base on questionnaire type.
38 changes: 38 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import js from '@eslint/js'
import globals from 'globals'
import react from 'eslint-plugin-react'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'

export default [
{
files: ['**/*.{js,jsx}'],
ignores: ['dist'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
parserOptions: {
ecmaVersion: 'latest',
ecmaFeatures: { jsx: true },
sourceType: 'module',
},
},
settings: { react: { version: '18.3' } },
plugins: {
react,
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...js.configs.recommended.rules,
...react.configs.recommended.rules,
...react.configs['jsx-runtime'].rules,
...reactHooks.configs.recommended.rules,
'react/jsx-no-target-blank': 'off',
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
},
]
13 changes: 13 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
Loading

0 comments on commit 951bc53

Please sign in to comment.