account preferences page

new page to change user's recording preferences
This commit is contained in:
Nuwan 2025-02-03 12:25:21 +05:30
parent 3677181e09
commit 5ff152233b
8 changed files with 176 additions and 6 deletions

View File

@ -0,0 +1,34 @@
/// <reference types="cypress" />
import makeFakeUser from '../../factories/user';
describe('Account Preferences Feature', () => {
beforeEach(() => {
// Log in to the application or navigate to the account page
// where the change email feature is available
const currentUser = makeFakeUser({
email: 'sam@example.com',
recording_pref: 0
});
cy.stubAuthenticate({ ...currentUser });
cy.intercept('POST', /\S+\/users\S+/, {
statusCode: 200
}).as('updateUser');
cy.visit('/account/preferences');
});
it('should display the current recording preference', () => {
// Assert that the current recording preference is displayed
cy.get('[data-testid=recording_pref_none]').should('be.checked');
});
it('should save the new recording preference', () => {
// Select a new recording preference
cy.get('[data-testid=recording_pref_my_audio]').check('1');
cy.wait('@updateUser');
// Assert that the new recording preference is saved
cy.contains('Recording preference saved successfully.');
});
});

View File

@ -37,6 +37,7 @@ import JKEditProfile from '../page/JKEditProfile';
import JKEditAccount from '../page/JKEditAccount'; import JKEditAccount from '../page/JKEditAccount';
import JKAccountSubscription from '../page/JKAccountSubscription'; import JKAccountSubscription from '../page/JKAccountSubscription';
import JKPaymentHistory from '../page/JKPaymentHistory'; import JKPaymentHistory from '../page/JKPaymentHistory';
import JKAccountPreferences from '../page/JKAccountPreferences';
import JKAffiliateProgram from '../affiliate/JKAffiliateProgram'; import JKAffiliateProgram from '../affiliate/JKAffiliateProgram';
import JKAffiliatePayee from '../affiliate/JKAffiliatePayee'; import JKAffiliatePayee from '../affiliate/JKAffiliatePayee';
@ -294,6 +295,7 @@ function JKDashboardMain() {
<PrivateRoute path="/account/identity" component={JKEditAccount} /> <PrivateRoute path="/account/identity" component={JKEditAccount} />
<PrivateRoute path="/account/subscription" component={JKAccountSubscription} /> <PrivateRoute path="/account/subscription" component={JKAccountSubscription} />
<PrivateRoute path="/account/payments" component={JKPaymentHistory} /> <PrivateRoute path="/account/payments" component={JKPaymentHistory} />
<PrivateRoute path="/account/preferences" component={JKAccountPreferences} />
<PrivateRoute path="/affiliate/program" component={JKAffiliateProgram} /> <PrivateRoute path="/affiliate/program" component={JKAffiliateProgram} />
<PrivateRoute path="/affiliate/payee" component={JKAffiliatePayee} /> <PrivateRoute path="/affiliate/payee" component={JKAffiliatePayee} />
<PrivateRoute path="/affiliate/links" component={JKAffiliateLinks} /> <PrivateRoute path="/affiliate/links" component={JKAffiliateLinks} />

View File

@ -0,0 +1,106 @@
import React, { useState, useEffect } from 'react'
import { Row, Col, Card, CardHeader, CardBody, Form, FormGroup, Label, Input } from 'reactstrap';
import FalconCardHeader from '../common/FalconCardHeader';
import { useTranslation } from 'react-i18next';
import { useAuth } from '../../context/UserAuth';
import { updateUser } from '../../helpers/rest';
import { toast } from 'react-toastify';
import { useForm } from 'react-hook-form';
const JKAccountPreferences = () => {
const { t } = useTranslation('account');
const { currentUser } = useAuth();
const [selectedPref, setSelectedPref] = useState(null);
const [selectedPrefV2, setSelectedPrefV2] = useState(null);
const {
register,
setValue
} = useForm();
useEffect(() => {
if (currentUser) {
setValue('recording_pref', currentUser.recording_pref);
setSelectedPrefV2(currentUser.recording_pref);
}
}, [currentUser]);
//save the selected preference to the database
useEffect(() => {
if (!currentUser || selectedPref === null) {
return;
}
const params = {
recording_pref: selectedPref
}
updateUser(currentUser.id, params).then(response => {
setSelectedPrefV2(selectedPref);
toast.success(t('preferences.recording_preferences.save_success'));
}).catch(error => {
console.log(error);
toast.error(t('preferences.recording_preferences.save_error'));
});
}, [selectedPref]);
return (
<Card>
<FalconCardHeader title={t('preferences.page_title')} titleClass="font-weight-bold" />
<CardBody className="pt-3" style={{ backgroundColor: '#edf2f9' }}>
<Row>
<Col className='mb-2'>
<Card>
<CardHeader>
<h5>{t('preferences.recording_preferences.title')}</h5>
</CardHeader>
<CardBody className="bg-light" style={{ minHeight: 300 }}>
<small>
{t('preferences.recording_preferences.help_text')}
</small>
<Form noValidate className="mt-2 pl-4">
<FormGroup>
<Input
{...register('recording_pref')}
checked={selectedPref === 0 || selectedPrefV2 === 0}
type='radio'
value="0"
data-testid="recording_pref_none"
onClick={() => setSelectedPref(0)} />
<Label for="exampleSelect">{t('preferences.recording_preferences.options.none')}</Label>
</FormGroup>
<FormGroup>
<Input
{...register('recording_pref')}
checked={selectedPref === 1 || selectedPrefV2 === 1}
type='radio'
value="1"
data-testid="recording_pref_my_audio"
onClick={() => setSelectedPref(1)} />
<Label for="exampleSelect">{t('preferences.recording_preferences.options.my_audio')}</Label>
</FormGroup>
<FormGroup>
<Input
{...register('recording_pref')}
checked={selectedPref === 2 || selectedPrefV2 === 2}
type='radio'
value="2"
data-testid="recording_pref_my_audio_and_session_mix"
onClick={() => setSelectedPref(2)} />
<Label for="exampleSelect">{t('preferences.recording_preferences.options.my_audio_and_session_mix')}</Label>
</FormGroup>
</Form>
</CardBody>
</Card>
</Col>
<Col className='d-none d-lg-block'></Col>
<Col className='d-none d-lg-block'></Col>
</Row>
</CardBody>
</Card>
)
}
export default JKAccountPreferences

View File

@ -24,7 +24,6 @@
"alerts": { "alerts": {
"updated": "Your account identity has been updated.", "updated": "Your account identity has been updated.",
"confirmation_email_sent": "A confirmation email has been sent to your email address. Please click the link in the email to confirm your email address." "confirmation_email_sent": "A confirmation email has been sent to your email address. Please click the link in the email to confirm your email address."
} }
}, },
"password_form": { "password_form": {
@ -52,8 +51,20 @@
"help_text_p2": "to reset your password, and you will receive an email with instructions on how to reset your password to the email address associated with your JamKazam account." "help_text_p2": "to reset your password, and you will receive an email with instructions on how to reset your password to the email address associated with your JamKazam account."
} }
} }
},
"preferences": {
"page_title": "Preferences",
"recording_preferences": {
"title": "Recording",
"help_text": "Record the follwing selection on my computer when someone else in a session I'm playing in starts a recording.",
"options": {
"none": "Don't record anything on my computer",
"my_audio": "Record my own audio tracks",
"my_audio_and_session_mix": "Record my own audio tracks and the session mix"
},
"save_success": "Recording preference saved successfully.",
"save_error": "Failed to save recording preference. Please try again later."
}
}, },
"subscription": { "subscription": {
"page_title": "Subscription", "page_title": "Subscription",
@ -71,7 +82,6 @@
"part1": "To compare the features available for different subscription plans ", "part1": "To compare the features available for different subscription plans ",
"click_here": "click here", "click_here": "click here",
"part2": " to view a help article on our available plans." "part2": " to view a help article on our available plans."
} }
}, },
"play_time": { "play_time": {
@ -83,7 +93,7 @@
"changed_to_free_plan": "You have chosen to go back down to the FREE PLAN. Your subscription will be canceled, and you will keep your plan until the end of the current billing cycle.", "changed_to_free_plan": "You have chosen to go back down to the FREE PLAN. Your subscription will be canceled, and you will keep your plan until the end of the current billing cycle.",
"failed_to_change_plan": "Failed to update subscription plan. Please try again later. Please contact support@jamkazam.com if you continue to have problems.", "failed_to_change_plan": "Failed to update subscription plan. Please try again later. Please contact support@jamkazam.com if you continue to have problems.",
"changed_plan_successfully": "You have successfully updated your subscription plan." "changed_plan_successfully": "You have successfully updated your subscription plan."
} }
}, },
"payments": { "payments": {
"page_title": "Payment History", "page_title": "Payment History",
@ -98,4 +108,4 @@
"load_more": "Load More", "load_more": "Load More",
"loading": "Loading..." "loading": "Loading..."
} }
} }

View File

@ -59,6 +59,7 @@ export const accountRoutes = {
{ to: '/account/subscription', name: 'Subscription'}, { to: '/account/subscription', name: 'Subscription'},
{ to: '/account/payments', name: 'Payment History'}, { to: '/account/payments', name: 'Payment History'},
{ to: '/account/payment-method', name: 'Payment Method'}, { to: '/account/payment-method', name: 'Payment Method'},
{ to: '/account/preferences', name: 'Preferences'},
] ]
} }

View File

@ -0,0 +1,9 @@
class AddRecordingPrefToUsers < ActiveRecord::Migration
def self.up
execute "ALTER TABLE users ADD COLUMN recording_pref INT"
execute "UPDATE users SET recording_pref = 0"
end
def self.down
execute "ALTER TABLE users DROP COLUMN recording_pref"
end
end

View File

@ -66,6 +66,11 @@ module JamRuby
ESCALATION_REASON_OTHER = "Other" ESCALATION_REASON_OTHER = "Other"
ESCALATION_REASONS = [ESCALATION_REASON_NO_AUDIO_STREAM, ESCALATION_REASON_NO_VIDEO_STREAM, ESCALATION_REASON_SETUP_WIZARD_FAILURE, ESCALATION_REASON_OTHER] ESCALATION_REASONS = [ESCALATION_REASON_NO_AUDIO_STREAM, ESCALATION_REASON_NO_VIDEO_STREAM, ESCALATION_REASON_SETUP_WIZARD_FAILURE, ESCALATION_REASON_OTHER]
enum :recording_pref, [
{no_recording: 0},
{own_tracks: 1},
{own_tracks_and_session_mix: 2}
]
devise :database_authenticatable, :recoverable, :rememberable devise :database_authenticatable, :recoverable, :rememberable

View File

@ -57,6 +57,7 @@ class ApiUsersController < ApiController
photo_url: current_user.photo_url, photo_url: current_user.photo_url,
show_free_jamtrack: current_user.show_free_jamtrack?, show_free_jamtrack: current_user.show_free_jamtrack?,
is_affiliate_partner: current_user.affiliate_partner.present?, is_affiliate_partner: current_user.affiliate_partner.present?,
recording_pref: current_user.recording_pref,
}, status: 200 }, status: 200
end end
@ -246,6 +247,8 @@ class ApiUsersController < ApiController
@user.retailer_interest = !!params[:retailer_interest] @user.retailer_interest = !!params[:retailer_interest]
@user.desired_package = LessonPackageType.find_by_package_type!(params[:desired_package]) if params.has_key?(:desired_package) @user.desired_package = LessonPackageType.find_by_package_type!(params[:desired_package]) if params.has_key?(:desired_package)
@user.accept_desktop_notifications = params[:accept_desktop_notifications] if params.has_key?(:accept_desktop_notifications) @user.accept_desktop_notifications = params[:accept_desktop_notifications] if params.has_key?(:accept_desktop_notifications)
@user.recording_pref = params[:recording_pref] if params.has_key?(:recording_pref)
if @user.save if @user.save
test_drive_package_details = params[:test_drive_package] test_drive_package_details = params[:test_drive_package]