Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
115 commits
Select commit Hold shift + click to select a range
7cda8a8
Border on select and multinput
Oct 14, 2025
0c25712
Small design adjustments
Oct 17, 2025
19078e3
Changed grid/list button to look like figma
Oct 17, 2025
68cfb62
Added translation to rest of the english words
MikkelBLarsen Oct 18, 2025
cf592ed
feat: (web) file upload to course (#29)
Alb9ert Oct 19, 2025
d816051
Test
ollioddi Oct 19, 2025
89121fd
DataToolBar fix
Oct 20, 2025
3758c29
Feat(web): Multi-select add item callback & ref. Course Editor add ne…
ollioddi Oct 20, 2025
8f8884a
Update course-card.tsx
Oct 20, 2025
8d03ea5
Update course-card.tsx
Oct 20, 2025
66a2758
Merge pull request #42 from ErasmusEgalitarian/design-changes
DandingB Oct 20, 2025
69bce29
Feat(Web): Auth Context (#30)
ollioddi Oct 20, 2025
dc63e0b
Course editor menu
ollioddi Oct 20, 2025
2b10a1c
Unchecked color
ollioddi Oct 20, 2025
363e90e
Merge branch 'dev' into feat/translation
Alb9ert Oct 20, 2025
0697d1a
Merge pull request #54 from ErasmusEgalitarian/feat/translation
Alb9ert Oct 20, 2025
00a36ec
Merge pull request #55 from ErasmusEgalitarian/web/editor-menu
Alb9ert Oct 20, 2025
357977b
removed workflow for now
Alb9ert Oct 20, 2025
f7c39a3
fix
Smidtty Oct 24, 2025
a77baea
feat: (web) file upload to course (#29)
Alb9ert Oct 19, 2025
263cac3
Test
ollioddi Oct 19, 2025
3ef9304
removed workflow for now
Alb9ert Oct 20, 2025
5674165
Merge branch 'dev' of https://github.com/ErasmusEgalitarian/educado-b…
Johny1511 Oct 27, 2025
ffae260
strapi 5.29 version
Johny1511 Oct 27, 2025
c9acad6
Package lock
ollioddi Oct 27, 2025
1a89962
Bump vite from 7.1.9 to 7.1.11 in /web (#58)
dependabot[bot] Oct 30, 2025
098618a
Feat: 🚀 Add Turborepo, CI/CD Pipelines & Comprehensive Documentation …
ollioddi Oct 30, 2025
a050999
Add environment to build pipelines
ollioddi Oct 30, 2025
8d9debb
Test build pipeline
ollioddi Oct 30, 2025
a3cc570
Fix npm not installing (#73)
ollioddi Nov 3, 2025
da89b1f
update strapi
Alb9ert Nov 4, 2025
8f1c853
hello
Alb9ert Nov 4, 2025
e85a371
Update lockfile to test npm ci
ollioddi Nov 4, 2025
590eea9
Merge pull request #74 from ErasmusEgalitarian/chore/bump-strapi
Alb9ert Nov 4, 2025
7a84bb2
Test build
ollioddi Nov 4, 2025
d0ded5f
Fix: Restore OpenAPI types for client generation via Hey API + depre…
ollioddi Nov 4, 2025
1e4ea9d
Test
ollioddi Nov 4, 2025
4f4ad53
hm
ollioddi Nov 4, 2025
24e0a09
Foo
ollioddi Nov 4, 2025
9f3fa41
Test
ollioddi Nov 4, 2025
698b019
Test CI
ollioddi Nov 4, 2025
2a782fd
Test CI again...
ollioddi Nov 4, 2025
8c4530e
CI..
ollioddi Nov 4, 2025
f424f52
Build works. Cleanup tagging
ollioddi Nov 4, 2025
3482efe
Full CI test with Strapi changes
ollioddi Nov 4, 2025
289ee09
Test build
ollioddi Nov 4, 2025
24282f8
CI: Test build
ollioddi Nov 4, 2025
10e879a
scripts
Alb9ert Oct 28, 2025
e82181c
moved btn
Alb9ert Oct 28, 2025
d0ca8f1
fixed
Alb9ert Oct 28, 2025
46d9dd0
ui fix
Alb9ert Oct 28, 2025
f94bb74
ready for backend
Alb9ert Oct 28, 2025
f5ff767
fix
Alb9ert Nov 4, 2025
633f164
delete lock file
Alb9ert Nov 4, 2025
a3587e8
fix
Alb9ert Nov 4, 2025
2942566
fix
Alb9ert Nov 4, 2025
aeb9a1a
fix
Alb9ert Nov 6, 2025
0c0d06a
Merge pull request #77 from ErasmusEgalitarian/feat/web-draft
Alb9ert Nov 8, 2025
2e933ac
(chore/web) cleanup dependencies (#70)
ollioddi Nov 9, 2025
c3eb639
data-table selection V1 (#78)
ollioddi Nov 9, 2025
65f290c
0.2.0
ollioddi Nov 10, 2025
269e9b7
Add debug steps for registry access in build workflows and update rel…
ollioddi Nov 10, 2025
5487d33
sync: merge main v0.3.0 release back to dev
ollioddi Nov 10, 2025
fbad72f
fix: strip 'v' prefix from version tags for proper semver parsing
ollioddi Nov 10, 2025
71ffc06
fix: disable provenance attestations
ollioddi Nov 10, 2025
ff746b6
sync: merge main release back to dev
ollioddi Nov 10, 2025
e4cb8f8
Include node types (process.env)
ollioddi Nov 11, 2025
79484de
[US-0004] - Content Creator Login #53
CelestrialDragon Nov 11, 2025
e9cd66d
User relation
EmilLykke Nov 11, 2025
0819fa5
Updated
EmilLykke Nov 11, 2025
6c7b801
Removed .env.example from strapi, added mise config and moved .nvmrc
Alfenstein8 Nov 13, 2025
a621a66
fix: Update Swagger to use proper merged spec (#90)
ollioddi Nov 13, 2025
c87c3e5
remove relation
EmilLykke Nov 13, 2025
2c1ba60
updated return type and added policies to routes
EmilLykke Nov 13, 2025
2ae240a
updated some endpoints to not require auth
EmilLykke Nov 13, 2025
9a2a7cb
updated strapi spech with new definitions for endpoints
EmilLykke Nov 13, 2025
98f2f56
small change to registartion verifiedAt
EmilLykke Nov 13, 2025
361942a
Merge pull request #95 from ErasmusEgalitarian/remove-strapi-env-and-…
Alfenstein8 Nov 13, 2025
9adf6ab
updated content creator login function name change
EmilLykke Nov 14, 2025
37264fa
real generated
EmilLykke Nov 14, 2025
8288965
Login.tsx working
EmilLykke Nov 14, 2025
70fd8ff
updated strapi
EmilLykke Nov 14, 2025
d99dc89
Strapi login for content creators
EmilLykke Nov 14, 2025
a0fe523
Small update
EmilLykke Nov 14, 2025
075b8b1
Overwrite upload route
EmilLykke Nov 14, 2025
36d49d4
added comment
EmilLykke Nov 14, 2025
dc47c62
small changes
EmilLykke Nov 15, 2025
73f77a5
PR comments
EmilLykke Nov 15, 2025
a14aa27
added rate limit to content creator login
EmilLykke Nov 15, 2025
395978f
student reset password update reate limit
EmilLykke Nov 15, 2025
beac635
verified at fixed
EmilLykke Nov 15, 2025
33e0832
Fixed order of verified check
EmilLykke Nov 15, 2025
24e99af
Merge pull request #98 from ErasmusEgalitarian/505-integrating-backen…
EmilLykke Nov 15, 2025
a496d99
feat: add ESLint diffing tool to check only changed files (#96)
ollioddi Nov 16, 2025
aeb5f72
Add required durationHours field to course schema
edmxa Nov 17, 2025
838a4d9
Change course durationHours to integer type
edmxa Nov 17, 2025
6c9ecfb
Update course duration label to 'horas'
edmxa Nov 17, 2025
15faa7a
Remove unused durationHours prop from CourseCard, andChange durationH…
edmxa Nov 17, 2025
805902f
Add durationHours field to course models and API and Update SDK files
edmxa Nov 17, 2025
5caa82f
Merge pull request #104 from ErasmusEgalitarian/Fetch-hours-from-back…
edmxa Nov 17, 2025
939f31d
Feature/tailwind for login (#113)
CelestrialDragon Nov 19, 2025
04fbad5
Remove healthcheck (#109)
ollioddi Nov 23, 2025
42d87cc
enhancement: extend DataDisplay component with ref support (#86)
ollioddi Nov 23, 2025
ec2318c
Fix/notifications (#103)
DandingB Nov 24, 2025
7605dae
Make lastName required for Content Creator (#122)
edmxa Nov 24, 2025
841b0ab
Override controllers to allow populate (#121)
EmilLykke Nov 25, 2025
ff1facf
Migration of all icons to a singular library (mdi) (#100)
Smidtty Nov 25, 2025
aa5f5ad
updated package lock (#126)
Fahnoee Nov 26, 2025
4639a42
Added a (pre)vious slide function that was missing for some reason (#…
PeterDunlop Nov 26, 2025
0bc7486
Implented:
RasmusJensen1 Dec 3, 2025
d035e59
feat: update profile picture handling and improve payload structure f…
RasmusJensen1 Dec 11, 2025
308e910
Merge branch 'dev' into us-0092-update-profile-picture-content-creator
RasmusJensen1 Dec 11, 2025
a79d8be
Merge branch 'dev' into us-0092-update-profile-picture-content-creator
RasmusJensen1 Dec 11, 2025
fa9bb21
Refactor course columns, enhance file upload hook, and improve profil…
RasmusJensen1 Dec 11, 2025
0c94c6d
Merge branch 'dev' into us-0092-update-profile-picture-content-creator
RasmusJensen1 Dec 11, 2025
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
1,513 changes: 1,433 additions & 80 deletions openapi/strapi-spec.json

Large diffs are not rendered by default.

55 changes: 1 addition & 54 deletions package-lock.json

Large diffs are not rendered by default.

1,513 changes: 1,433 additions & 80 deletions strapi/public/openapi/strapi-spec.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@
"target": "api::dashboard-activity.dashboard-activity",
"mappedBy": "content_creator"
},
"profilePicture": {
"type": "media",
"multiple": false,
"required": false,
"allowedTypes": ["images"]
},
"isAdmin": {
"type": "boolean",
"default": false
Expand Down

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions strapi/types/generated/contentTypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,7 @@ export interface ApiContentCreatorContentCreator
Schema.Attribute.SetMinMaxLength<{
minLength: 8;
}>;
profilePicture: Schema.Attribute.Media<'images'>;
publishedAt: Schema.Attribute.DateTime;
rejectionReason: Schema.Attribute.String &
Schema.Attribute.SetMinMaxLength<{
Expand Down
5 changes: 5 additions & 0 deletions web/eslint.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ export default [
rules: {
// Disable unified-signatures rule due to crashes in @typescript-eslint/eslint-plugin
"@typescript-eslint/unified-signatures": "off",
// Prevents bugs from using "truthy" or "falsy" values in conditions.
"@typescript-eslint/strict-boolean-expressions": [
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the rule

"error",
{ allowString: false, allowNumber: false, allowNullableObject: true },
],
// Prevents `console.log` (In prod), but allows `console.warn` and `console.error`.
"no-console": ["error", { allow: ["warn", "error"] }],
// Enforces the project's coding conventions for naming variables, functions, etc.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import {
} from "../api/course-mutations";
import { difficultyToTranslation } from "../lib/difficulty-to-translation";


import CategoryCreateModal from "./category-create-modal";

/* ------------------------------- Interfaces ------------------------------- */
Expand Down
1 change: 1 addition & 0 deletions web/src/features/course/lib/course-columns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ export const createCourseColumns = ({
},
},
{

accessorKey: "difficulty",
header: t("difficulty.difficulty"),
cell: ({ row }) => {
Expand Down
40 changes: 37 additions & 3 deletions web/src/features/media/hooks/use-file-upload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,35 @@ export interface FileWithMetadata {
caption: string;
}

// Define the single file object type from the API response
type UploadedFile = {
id: number;
documentId: string;
name: string;
alternativeText?: string | null;
caption?: string | null;
width?: number;
height?: number;
formats?: { [key: string]: unknown };
hash: string;
ext?: string;
mime: string;
size: number;
url: string;
previewUrl?: string | null;
folder?: number;
folderPath: string;
provider: string;
provider_metadata?: { [key: string]: unknown } | null;
createdAt: string;
updatedAt: string;
createdBy?: number;
updatedBy?: number;
};

// eslint-disable-next-line sonarjs/class-name, @typescript-eslint/naming-convention
interface useFileUploadReturn {
uploadFile: (files: FileWithMetadata[]) => Promise<UploadPostResponses[200] | undefined>;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This type is driven by the openapi spec. Why define and maintain it manually?

uploadFile: (files: FileWithMetadata[]) => Promise<UploadedFile[] | undefined>;
isUploading: boolean;
}

Expand Down Expand Up @@ -64,8 +90,16 @@ export const useFileUpload = (): useFileUploadReturn => {
// Wait for all uploads to complete
const uploadedFiles = await Promise.all(uploadPromises);

// Flatten the results since each upload might return an array
const flattenedFiles = uploadedFiles.flat();
// Flatten the results since each upload might return a single object or an array
const flattenedFiles: UploadedFile[] = [];

for (const result of uploadedFiles) {
if (Array.isArray(result)) {
flattenedFiles.push(...result);
} else {
flattenedFiles.push(result);
}
}

return flattenedFiles;
} catch (error) {
Expand Down
103 changes: 69 additions & 34 deletions web/src/features/user/components/PersonalInformation.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,32 @@
//Imports
import { useEffect, useState } from "react";
import { useState } from "react";

import Modals from "@/auth/components/Modals";
import { getBaseApiUrl } from "@/shared/config/api-config";

import { BACKEND_URL } from "../../../shared/config/environment";
//Types
interface PersonalInformationFormProps {
formData: {
UserName: string;
UserEmail: string;
bio?: string;
linkedin?: string;
};
errors: {
UserName?: { message?: string };
UserEmail?: { message?: string };
linkedin?: { message?: string };
};
handleCharCountBio: () => number;
toggleMenu1: boolean;
imageClick: () => void;
handleFileChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
handleProfilePictureDelete: () => void;
myRef: React.RefObject<HTMLInputElement>;
register: any; // react-hook-form register function
handleInputChange: (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
profilePictureUrl?: string;
}

//Exporting UI content&structure of
export default function PersonalInformationForm({
Expand All @@ -13,20 +36,12 @@
toggleMenu1,
imageClick,
handleFileChange,
handleProfilePictureDelete,
myRef,
register,
handleInputChange,
}: {
formData: any;
errors: any;
handleCharCountBio: any;
toggleMenu1: any;
imageClick: any;
handleFileChange: any;
myRef: any;
register: any;
handleInputChange: any;
}) {
profilePictureUrl,
}: PersonalInformationFormProps) {
//State for pop up modals
const [isModalOpen, setIsModalOpen] = useState(false);
const [isSecondModalOpen, setIsSecondModalOpen] = useState(false);
Expand All @@ -42,31 +57,39 @@
setModalInputValue(numericInput);
setIntError(!/^[0-9]*$/.test(e.target.value));
};
const getUserImage = async () => {
const response = await fetch(
`http://localhost:8888/api/bucket/${formData.photo}`,
);

// Helper function to construct the full image URL from Strapi
// Handles both absolute URLs (starting with http) and relative URLs from Strapi
const getImageUrl = (url: string | undefined): string => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exists in media utils

if (!url) return "";
if (url.startsWith('http')) return url;

let strapiBase = getBaseApiUrl();
if (strapiBase.endsWith('/api')) {
strapiBase = strapiBase.slice(0, -4);
}
return `${strapiBase}${url}`;
};
useEffect(() => {
getUserImage();
}, []);

return (
<>
{/* content of personal information when drop down button is clicked */}
{toggleMenu1 && (
/* Image */
<div className="border border-[#166276] p-4 rounded-b-lg text-left bg-white shadow-xl">
{/* Display selected image if uploaded, otherwise display icon with initials*/}
{formData.photo ? (
<img
src={`${BACKEND_URL}/api/bucket/${formData.photo}`}
className="w-[120px] h-[120px] p-[0px] bg-cyan-800 rounded-[60px] border-2 border-white inline-flex"
alt=""
/>
{profilePictureUrl ? (
<div className="relative inline-block">
<img
src={getImageUrl(profilePictureUrl)}
className="w-[120px] h-[120px] rounded-full border-2 border-white object-cover"
alt="Profile Picture"
/>

Check warning on line 87 in web/src/features/user/components/PersonalInformation.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Redundant alt attribute. Screen-readers already announce `img` tags as an image. You don’t need to use the words `image`, `photo,` or `picture` (or any specified custom words) in the alt prop.

See more on https://sonarcloud.io/project/issues?id=ErasmusEgalitarian_educado-backend&issues=AZsOGTDwm-gH-i2lCTN-&open=AZsOGTDwm-gH-i2lCTN-&pullRequest=143
</div>
) : (
<div
onClick={imageClick}
className="w-[120px] h-[120px] p-[30px] bg-cyan-800 rounded-[60px] border-2 border-white justify-center items-center gap-[30px] inline-flex"
className="w-[120px] h-[120px] p-[30px] bg-cyan-800 rounded-[60px] border-2 border-white justify-center items-center gap-[30px] inline-flex cursor-pointer"
>
<div className="text-white text-4xl font-bold font-['Montserrat']">
{formData.UserName.charAt(0).toUpperCase()}
Expand All @@ -82,13 +105,25 @@
style={{ display: "none" }}
/>

{/* On button click change image*/}
<button
className=" p-7 text-center text-cyan-800 text-lg font-bold font-['Montserrat'] underline"
onChange={handleFileChange}
>
Alterar foto de perfil
</button>
{/* Buttons for changing/deleting profile picture */}
<div className="flex gap-4 mt-2">
<button
type="button"
onClick={imageClick}
className="p-7 text-center text-cyan-800 text-lg font-bold font-['Montserrat'] underline"
>
Alterar foto de perfil
</button>
{profilePictureUrl && (
<button
type="button"
onClick={() => handleProfilePictureDelete()}
className="p-7 text-center text-red-500 text-lg font-bold font-['Montserrat'] underline"
>
Deletar foto
</button>
)}
</div>
<div className="grid grid-cols-2 gap-3 mt-7">
{/* Username */}
<div className="flex flex-col ">
Expand Down
Loading
Loading