Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
624d0a6
added priming to StopSignal
softwarebyze Jun 10, 2023
b2601ad
added subliminal priming to gonogo
softwarebyze Jun 10, 2023
08dd096
Merge branch 'main' into subliminal-priming
softwarebyze Oct 8, 2023
8580c2d
Merge pull request #80 from softwarebyze/main
softwarebyze Oct 14, 2023
7899514
Merge branch 'main' into subliminal-priming
softwarebyze Oct 20, 2023
a3b3221
added typegen npm script
softwarebyze Oct 21, 2023
285a406
added priming picture so it prefetches
softwarebyze Oct 25, 2023
42e76dd
added columns for priming
softwarebyze Oct 25, 2023
d3a0dae
added negative priming placeholder image
softwarebyze Oct 25, 2023
53006bc
use string for gsession_created_at
softwarebyze Oct 25, 2023
82f4e15
cache negative priming image
softwarebyze Oct 25, 2023
6ef9877
positive and negative priming are working nicely
softwarebyze Oct 25, 2023
24f7778
updated test to have 16 unique low-cal foods, 16 unique high-cal food…
softwarebyze Oct 26, 2023
60d49bb
store primingCategories, primingImageSrcs in images.ts
softwarebyze Oct 26, 2023
c2dd478
fixed priming times
softwarebyze Oct 26, 2023
d60f991
as far as i can tell, positive and negative priming are working reall…
softwarebyze Oct 26, 2023
547538b
Merge pull request #86 from softwarebyze/85-add-positive-priming-to-s…
softwarebyze Oct 26, 2023
a21b58c
Merge remote-tracking branch 'origin' into subliminal-priming
softwarebyze Dec 24, 2023
cd9c795
Merge branch 'main' into subliminal-priming
softwarebyze Jan 26, 2024
f647f06
Add new priming images and remove old ones
softwarebyze Jan 28, 2024
20cb085
Merge pull request #96 from softwarebyze/95-update-priming-images
softwarebyze Jan 28, 2024
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
12 changes: 0 additions & 12 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import TaskPage from './components/TaskPage'
import UserPage from './components/UserPage'
import { useAuth } from './contexts/AuthContext'
import { UNHEALTHY_IMAGE_COUNT } from './data/images'
import { images } from './data/images.json'
import { tasks } from './data/tasks.json'
import { useFoodRatings } from './hooks/useFoodRatings'
import './main.css'
Expand Down Expand Up @@ -43,17 +42,6 @@ export default function App() {
return (
<BrowserRouter>
{session && <Nav />}
{images?.map((food) => (
<img
key={food.id}
src={food.src}
alt={'food'}
style={{
visibility: 'hidden',
height: '1px',
}}
/>
))}
<Routes>
<Route
path="/"
Expand Down
2 changes: 1 addition & 1 deletion src/components/DotProbe.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ export default function DotProbe({

const taskResponseData = {
user_id: session!.user.id,
gsession_created_at: taskStartedAt,
gsession_created_at: taskStartedAt.toLocaleDateString(),
game_slug: 'dotprobe',
assessment: 'TEST',
phase: 0,
Expand Down
142 changes: 80 additions & 62 deletions src/components/GoNoGo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
} from '../types/Task'
import { recordTaskResponse } from '../utils/recordResponse'
import Break from './Break'
import { getPrimingImageSrc, primingCategories } from '../data/images'

function getGoNoGoTrialType(imageType: ImageType): GoNoGoTrialType {
switch (imageType) {
Expand Down Expand Up @@ -95,43 +96,32 @@ export default function GoNoGo({
setAverageResponse,
userImages,
}: GameProps) {
const taskData = useMemo(() => prepareTaskData(userImages, totalTrials), [])
const [currentTrialIndex, setCurrentTrialIndex] = useState<number>(0)
const [gameStage, setGameStage] = useState<GoNoGoGameStage>('cue')
const [gameStage, setGameStage] = useState<GoNoGoGameStage>('prime')
const [primingShownAt, setPrimingShownAt] = useState<number | null>(
Date.now()
)

const [numCorrect, setNumCorrect] = useState<number>(0)
const [totalTime, setTotalTime] = useState<number>(0)
const { image, error, interval } = stages[gameStage]

const taskData = useMemo(() => prepareTaskData(userImages, totalTrials), [])

useEffect(() => {
const healthyPercent =
taskData.filter((imgData) => imgData.imageType === 'healthy').length /
taskData.length
const unhealthyPercent =
taskData.filter((imgData) => imgData.imageType === 'unhealthy').length /
taskData.length
const waterPercent =
taskData.filter((imgData) => imgData.imageType === 'water').length /
taskData.length
const percentages = `
Healthy: ${Math.round(healthyPercent * 100)}%
Unhealthy: ${Math.round(unhealthyPercent * 100)}%
Water: ${Math.round(waterPercent * 100)}%
`
console.log('Go/No-Go', percentages)
}, [])

const { src, trialType, side, border, imageType } =
taskData[currentTrialIndex]
const { src, trialType, side, border } = taskData[currentTrialIndex]
const [cueTimestamp, setCueTimestamp] = useState<number | null>(null)
const [taskStartedAt, setTaskStartedAt] = useState(new Date())
const [pictureDelta, setPictureDelta] = useState<number | null>(null)
const [pictureShownAt, setPictureShownAt] = useState<number | null>(null)
const [intervalShownAt, setIntervalShownAt] = useState<number | null>(null)
const [jitterDur, setJitterDur] = useState<number | null>(null)
const [primingDur, setPrimingDur] = useState<number | null>(null)
const { session } = useAuth()

const isTrialWithPriming: boolean = true
const showPriming: boolean = isTrialWithPriming && gameStage === 'prime'
const primingType: 'positive' | 'negative' =
trialType === 'go' ? 'positive' : 'negative'
const primingImageSrc = getPrimingImageSrc(primingType)

useEffect(() => {
setAccuracy(Math.round((numCorrect / currentTrialIndex) * 10000) / 100)
}, [setAccuracy, numCorrect, currentTrialIndex])
Expand All @@ -147,6 +137,15 @@ export default function GoNoGo({
setPictureDelta(
pictureShownAt ? pictureShownAt - taskStartedAt.getTime() : null
)
if (primingShownAt) {
setPrimingDur(primingShownAt ? Date.now() - primingShownAt : null)
setPrimingShownAt(null)
}
}

function showPrime() {
setGameStage('prime')
setPrimingShownAt(Date.now())
}

function showInterval() {
Expand Down Expand Up @@ -197,7 +196,7 @@ export default function GoNoGo({
)

useEffect(() => {
if (gameStage !== 'cue') showCue()
if (gameStage !== 'cue') isTrialWithPriming ? showPrime() : showCue()
}, [currentTrialIndex])

function handleReaction(reaction: GoNoGoReaction) {
Expand All @@ -214,7 +213,7 @@ export default function GoNoGo({

const taskResponseData = {
user_id: session!.user.id,
gsession_created_at: taskStartedAt,
gsession_created_at: taskStartedAt.toLocaleDateString(),
game_slug: 'gonogo',
assessment: 'TEST',
phase: 0,
Expand All @@ -240,6 +239,11 @@ export default function GoNoGo({
target_index: side === 'left' ? 0 : 1,
picture_offset: side === 'left' ? 'LEFT' : 'RIGHT',
picture_list: src,
priming_dur: primingDur,
priming_picture: isTrialWithPriming ? primingImageSrc : null,
priming_category: isTrialWithPriming
? primingCategories[primingType]
: null,
}

recordTaskResponse(taskResponseData)
Expand All @@ -262,6 +266,9 @@ export default function GoNoGo({
useEffect(() => {
let timeout: NodeJS.Timeout
switch (gameStage) {
case 'prime':
timeout = setTimeout(showCue, times.prime)
break
case 'cue':
timeout = setTimeout(() => handleReaction('omission'), times.cue)
break
Expand All @@ -280,43 +287,54 @@ export default function GoNoGo({
return () => clearTimeout(timeout)
}, [gameStage])

if (gameStage === 'break') return <Break />

return interval ? (
<></>
) : (
<div className={`imageBox ${border} sized`}>
{image && (
<div className="columns is-mobile">
<div className="column">
{side === 'left' ? (
<img
onClick={() => handleReaction('left-commission')}
src={src}
/>
) : (
<div
onClick={() => handleReaction('left-commission')}
className="fill clickable"
></div>
)}
</div>
<div className="column">
{side === 'right' ? (
<img
onClick={() => handleReaction('right-commission')}
src={src}
/>
) : (
<div
onClick={() => handleReaction('right-commission')}
className="fill clickable"
></div>
)}
</div>
return (
<>
{gameStage === 'break' ? (
<Break />
) : interval ? (
<></>
) : (
<div className={`imageBox ${!showPriming && border} sized`}>
{showPriming && (
<img
src={primingImageSrc}
alt="prime image"
className="squeezed cursorDefault"
/>
)}
{!showPriming && image && (
<div className="columns is-mobile">
<div className="column">
{side === 'left' ? (
<img
onClick={() => handleReaction('left-commission')}
src={src}
/>
) : (
<div
onClick={() => handleReaction('left-commission')}
className="fill clickable"
></div>
)}
</div>
<div className="column">
{side === 'right' ? (
<img
onClick={() => handleReaction('right-commission')}
src={src}
/>
) : (
<div
onClick={() => handleReaction('right-commission')}
className="fill clickable"
></div>
)}
</div>
</div>
)}
{error && <div className="redCross">X</div>}
</div>
)}
{error && <div className="redCross">X</div>}
</div>
</>
)
}
11 changes: 11 additions & 0 deletions src/components/HiddenImageToCache.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default function HiddenImageToCache({
style,
...props
}: React.DetailedHTMLProps<
React.ImgHTMLAttributes<HTMLImageElement>,
HTMLImageElement
>) {
return (
<img style={{ visibility: 'hidden', height: '1px', ...style }} {...props} />
)
}
31 changes: 31 additions & 0 deletions src/components/LoginPage.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { images } from '../data/images.json'
import { supabase } from '../supabaseClient'
import HiddenImageToCache from './HiddenImageToCache'
import {
negativePrimingImageSrcs,
positivePrimingImageSrcs,
} from '../data/images'

export default function LoginPage() {
const [loading, setLoading] = useState(false)
Expand Down Expand Up @@ -97,6 +103,31 @@ export default function LoginPage() {
</div>
</div>
</section>
<div>
{images?.map((food) => (
<HiddenImageToCache key={food.id} src={food.src} alt={'food'} />
))}
{positivePrimingImageSrcs.map(
(src) =>
src && (
<HiddenImageToCache
key={src}
src={src}
alt={'positive priming image'}
/>
)
)}
{negativePrimingImageSrcs.map(
(src) =>
src && (
<HiddenImageToCache
key={src}
src={src}
alt={'negative priming image'}
/>
)
)}
</div>
</div>
)
}
Loading