Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/frontend/app/components/NavBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const NavBar: React.FC<NavBarProps> = ({ activeTab = 'Home', onTabChange }) => {
{ label: "Home", path: "/mainPage"},
{ label: "New Session", path: "/new-session"},
{ label: "Past Sessions", path: "/past-sessions"},
{label: "Current Session", path:"new-session/current-session"},
{label: "User Profile", path: "/user-profile"},
];

Expand Down
17 changes: 17 additions & 0 deletions app/frontend/app/components/RecordView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { ReactMediaRecorder } from "react-media-recorder";

const RecordView = () => (
<div>
<ReactMediaRecorder
video
render={({ status, startRecording, stopRecording, mediaBlobUrl }) => (
<div>
<p>{status}</p>
<button onClick={startRecording}>Start Recording</button>
<button onClick={stopRecording}>Stop Recording</button>
<video src={mediaBlobUrl} controls autoPlay loop />
</div>
)}
/>
</div>
);
42 changes: 42 additions & 0 deletions app/frontend/app/components/RecordingComponent.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@

import { useState } from 'react'
import { RecordPanelHost, useRecordPanel } from 'recordpanel'
import 'recordpanel/styles'

function RecordingComponent() {
const [recording, setRecording] = useState(null)
const recorder = useRecordPanel()

const handleCapture = async () => {
try {
const result = await recorder.capture({
cameraEnabled: true,
audioEnabled: true
})

setRecording(result)

// Download the recording
const a = document.createElement('a')
a.href = result.url
a.download = `recording-${Date.now()}.webm`
a.click()

// Clean up
URL.revokeObjectURL(result.url)
} catch (error) {
console.error('Recording failed:', error)
}
}

return (
<div>
<button onClick={handleCapture}>Record Screen</button>
{recording && (
<video src={recording.url} controls />
)}
</div>
)
}

export default RecordingComponent;
25 changes: 25 additions & 0 deletions app/frontend/app/components/ScreenshotTool.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React, { useRef, useState } from 'react';
import { useScreenshot } from 'use-react-screenshot';

const ScreenshotTool = () => {
const ref = useRef(null);
const [image, takeScreenshot] = useScreenshot();
const getImage = () => takeScreenshot(ref.current);

const width = 400;
return (
<div>
<div>
<button style={{ marginBottom: '10px' }} onClick={getImage}>
Take screenshot
</button>
</div>
<img width={width} src={image} alt={'Screenshot'} />
<div ref={ref}>
<p>
</p>
</div>
</div>
)
};
export default ScreenshotTool;
96 changes: 96 additions & 0 deletions app/frontend/app/components/VideoRecorder.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import React, { useState, useRef } from 'react';

const VideoRecorder = () => {
const [recording, setRecording] = useState(false);
const [videoURL, setVideoURL] = useState(null);

const mediaRecorderRef = useRef(null);
const liveVideoRef = useRef(null);
const chunksRef = useRef([]);

const startRecording = async () => {
try {
// 1. Request audio and video access
const stream = await navigator.mediaDevices.getUserMedia({
video: true,
audio: true
});

// 2. Show live preview to the user
if (liveVideoRef.current) {
liveVideoRef.current.srcObject = stream;
}

// 3. Initialize MediaRecorder
const recorder = new MediaRecorder(stream, { mimeType: 'video/webm' });
mediaRecorderRef.current = recorder;
chunksRef.current = [];

// 4. Handle data chunks
recorder.ondataavailable = (e) => {
if (e.data.size > 0) {
chunksRef.current.push(e.data);
}
};

// 5. Handle recording stop
recorder.onstop = () => {
const completeBlob = new Blob(chunksRef.current, { type: 'video/webm' });
const url = URL.createObjectURL(completeBlob);
setVideoURL(url);

// Stop all tracks to turn off camera/mic hardware lights
stream.getTracks().forEach(track => track.stop());
};

recorder.start();
setRecording(true);
} catch (err) {
console.error("Error accessing media devices:", err);
alert("Please allow camera and microphone access.");
}
};

const stopRecording = () => {
mediaRecorderRef.current.stop();
setRecording(false);
};

return (
<div style={{ padding: '20px', textAlign: 'center' }}>
<h2>Wellness Begins!</h2>

<div style={{ marginBottom: '20px' }}>
{/* Live Preview / Recorded Result */}
<video
ref={liveVideoRef}
src={!recording ? videoURL : undefined}
autoPlay
muted={recording} // Mute live preview to avoid feedback loops
controls={!recording}
style={{ width: '100%', maxWidth: '500px', backgroundColor: '#000' }}
/>
</div>

<div style={{ display: 'flex', gap: '10px', justifyContent: 'center' }}>
{!recording ? (
<button onClick={startRecording} style={btnStyle}>Start Recording</button>
) : (
<button onClick={stopRecording} style={{...btnStyle, backgroundColor: 'red'}}>Stop Recording</button>
)}

{videoURL && !recording && (
<a href={videoURL} download="recording.webm" style={linkStyle}>
Download Recording
</a>
)}
</div>
</div>
);
};

// Simple styles
const btnStyle = { padding: '10px 20px', cursor: 'pointer', backgroundColor: '#007bff', color: '#fff', border: 'none', borderRadius: '5px' };
const linkStyle = { padding: '10px 20px', textDecoration: 'none', backgroundColor: '#28a745', color: '#fff', borderRadius: '5px' };

export default VideoRecorder;
2 changes: 1 addition & 1 deletion app/frontend/app/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ export default [
route("login", "routes/login.tsx"),
route("new-session", "routes/NewSessionContainer.tsx"),
route("past-sessions", "routes/PastSessionsContainer.tsx"),
route("new-session/current-session", "routes/CurrentSessionContainer.tsx"),
route("mainPage/new-session/current-session", "routes/CurrentSessionContainer.tsx"),
route("user-profile", "routes/UserProfileContainer.tsx")
] satisfies RouteConfig;
10 changes: 9 additions & 1 deletion app/frontend/app/routes/CurrentSessionContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
import React from 'react';
import { RecordPanelHost, useRecordPanel } from 'recordpanel';
import RecordingComponent from '../components/RecordingComponent';
import VideoRecorder from '../components/VideoRecorder';
import ScreenshotTool from '../components/ScreenshotTool.jsx';

const CurrentSessionContainer: React.FC = () => {

return (
<div>
<h1>Placeholder: Session in progress</h1>
<ScreenshotTool />
<VideoRecorder />
</div>

);
}

export default CurrentSessionContainer;
Loading